理解JWT

概念

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。

JWT的组成
一个JWT就是一个由头部、载荷、签名三部分构成的字符串

载荷(payload)

1
2
3
4
5
6
7
8
9
10
11
12
{
"iss": "Online JWT Builder", //iss: 该JWT的签发者,是否使用是可选的;
"iat": 1416797419, //iat(issued at): 在什么时候签发的(UNIX时间),是否使用是可选的;
其他还有:
"exp": 1448333419, //exp(expires): 什么时候过期,这里是一个Unix时间戳,是否使用是可选的;
"aud": "www.example.com", //aud: 接收该JWT的一方,是否使用是可选的;
"sub": "jrocket@example.com", //sub: 该JWT所面向的用户,是否使用是可选的;
"GivenName": "Johnny",
"Surname": "Rocket",
"Email": "jrocket@example.com",
"Role": [ "Manager", "Project Administrator" ]
}

将上面json对象进行base64编码得到下列字符串,这个字符串我们称它为JWT的payload(载荷)

1
eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9

头部(header)

JWT还需要一个头部,用于描述关羽该JWT的最基本的信息,例如类型及签名所用算法等。

1
2
3
4
{
"typ": "JWT",
"alg": "HS256"
}

base64后得到

1
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

签名(signature)

将头部和载荷用.连接在一起,得到以下字符串

1
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0

接着我们对拼接的字符串用HS256算法进行加密。加密的时候我们还需要提供一个密钥(secret),之后得到签名(这里使用字符串mystar作为密钥)

1
rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

最后,头部、载荷、签名按顺序用.连接,我们就得到了完整的JWT

1
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

之后在请求url中就需要带上jwt字符串

1
https://your.awesome-app.com/make-friend/?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

流程

登录

第一次认证:第一次登录,用户从浏览器输入用户名/密码,提交后到服务器的登录处理的Action层(Login Action);

Login Action调用认证服务进行用户名密码认证,如果认证通过,Login Action层调用用户信息服务获取用户信息(包括完整的用户信息及对应权限信息);

返回用户信息后,Login Action从配置文件中获取Token签名生成的秘钥信息,进行Token的生成;

生成Token的过程中可以调用第三方的JWT Lib生成签名后的JWT数据;

完成JWT数据签名后,将其设置到COOKIE对象中,并重定向到首页,完成登录过程;

2017101715082214936902.png

请求认证

客户端(APP客户端或浏览器)通过GET或POST请求访问资源(页面或调用API);

认证服务作为一个Middleware HOOK 对请求进行拦截,首先在cookie中查找Token信息,如果没有找到,则在HTTP Authorization Head中查找;

如果找到Token信息,则根据配置文件中的签名加密秘钥,调用JWT Lib对Token信息进行解密和解码;

完成解码并验证签名通过后,对Token中的exp、nbf、aud等信息进行验证;

全部通过后,根据获取的用户的角色权限信息,进行对请求的资源的权限逻辑判断;

如果权限逻辑判断通过则通过Response对象返回;否则则返回HTTP 401;

20171017150822152726546.png

认识

一个token就是一些信息的集合
token中包含足够多的信息,以便在后续请求中减少查询数据库的几率
服务端需要对cookie和HTTP Authrorization Header进行Token信息的检查
基于上一点,可以用一套token认证代码来面对浏览器类客户端和费浏览器类客户端
因为token是呗签名的,所以我们可以认为一个可以解码认证通过的token是由我们系统发放的,其中带有的信息是合法有效的。

安全

确保验证过程的安全性

如何防范XSS attacks

扩展

单点登录(SSO)

Session方式来存储用户id,一开始用户的Session只会存储在一台服务器上。对于有多个子域名的站点,每个子域名至少会对应一台不同的服务器,例如:

www.taobao.com
nv.taobao.com
nz.taobao.com
login.taobao.com

所以如果要实现在login.taobao.com登录后,在其他的子域名下依然可以取到Session,这要求我们在多台服务器上同步Session。

使用JWT的方式则没有这个问题的存在,因为用户的状态已经被传送到了客户端。因此,我们只需要将含有JWT的Cookie的domain设置为顶级域名即可,例如

1
Set-Cookie: jwt=lll.zzz.xxx; HttpOnly; max-age=980000; domain=.taobao.com

注意domain必须设置为一个点加顶级域名,即.taobao.com。这样,taobao.com和*.taobao.com就都可以接受到这个Cookie,并获取JWT了。

又或者使用header的方式,完全不用考虑跨域

常见认证机制

Http basic auth

每次请求带有用户名密码

session配合cookie

Token Auth

  • token就是一些信息的集合
  • token中包含足够的信息,可减少后续请求中查询的次数,
  • 服务端需要对HTTP Authrorization Header 进行token信息的检查
  • 一套token认证代码可面对浏览器客户端和非浏览器客户端
  • token auth常用的就是jwt(或者可以加上Oauth,Oauth是一整套的流程,包括认证和授权两部分,使得第三方应用可以访问用户资源,JWT是一个轻巧的认证规范)

相对session-cookie的优点:

  • 支持跨域
  • 无状态:服务端无需保存信息
  • 更适合移动应用:
  • csrf: 因为不在依赖cookie,所以不需要考虑csrf的防范
  • 性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多
  • 基于标准化: api可以采用标准化的jwt(json web token)

FAQ

参考

基于token的web后台授权机制
JSON Web Token - 在Web应用间安全地传递信息
八幅漫画理解使用JSON Web Token设计单点登录系统
3种web会话管理的方式