JWT
基于token的用户认证原理:让用户输入账号和密码,认证通过后获得一个token(令牌),在token有效期里用户可以带着token访问特定资源。
开始token并没有一个统一标准,大家都各自使用自己的方案。后来出现了JWT(Json Web Token)这个标准。
JWT本质上是一个对JSON对象加密后的字符串。当服务器认证用户通过后,一个包含用户信息的json对象被加密后返回给用户,json对象:
{
"UserName": "老王",
"Role": "admin",
"Expire": "2019-01-10 20:10:00"
}
之后,用户访问服务器时,都要返回这个json对象。服务器只靠这个对象就可以识别用户身份,不需要再去查数据库。为了防止用户篡改数据,服务器在生成对象时将添加一个签名。
服务器不保存任何会话数据,也就是说,服务器变得无状态,从而更容易扩展。
JWT的结构
典型的JWT由三个部分组成,每个部分由一个点(.)分隔。
Header
Payload
Signature
header.payload.signature
Header
头部包含所使用的签名算法和令牌的类型(即JWT),这部分会被编码为Base64URL格式。
{
"alg": "HS256",
"typ": "JWT"
}
Base64URL的格式:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Base64URL
Base64编码后可能出现字符+和/,在URL中不能直接作为参数,Base64URL就是把字符+和/分别变成-和_。JWT有可能放在url中,所以要用Base64URL编码。
Payload
Playload包含实际要传输的信息,附带一些其他信息如过期时间、发行时间等。JWT指定了一些官方字段(claims)备用:
iss: 签发人
exp: 过期时间
iat: 签发时间
nbf: 生效时间
jti: 编号
sub: 主题
aud: 受众
除了官方字段,在这个部分还可以添加私有字段,例如:
{
"sub": "1234567890",
"name": "隔壁老王",
"iat": 1516239022
}
这部分也是Base64URL编码的:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IumalOWjgeiAgeeOiyIsImlhdCI6MTUxNjIzOTAyMn0
Signature
Signature部分是对前两部分的防篡改签名。将Header和Payload用Base64URL编码后,再用点(.)连接起来。然后使用签名算法和密钥对这个字符串进行签名:
signature = hmac_sha256(base64encode(header) + '.' + base64encode(payload), 'MY_SUPER_SECRET_KEY')
这个密钥(MY_SUPER_SECRET_KEY)只有服务器才知道,不能泄露给用户。
签名信息:
huj1R4oYsSxbIpecRwGcDBzqFkL9dXA88P2ouM5xhT8
组合在一起
3部分组合在一起,构成了完整的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IumalOWjgeiAgeeOiyIsImlhdCI6MTUxNjIzOTAyMn0.huj1R4oYsSxbIpecRwGcDBzqFkL9dXA88P2ouM5xhT8
JWT怎么用
浏览器接收到服务器发过来的jwt后,可以存储在Cookie或localStorage中。
之后,浏览器每次与服务器通信时都会带上JWT。可以将JWT放在Cookie中,会自动发送(不跨域),或将JWT放在HTTP请求头的授权字段中。
Authorization: Bearer
也可放在url中,或POST请求的数据体中。
注意
JWT默认是不加密的,但也可以加密,不加密时不宜在jwt中存放敏感信息
不要泄露签名密钥(MY_SUPER_SECRET_KEY)
jwt签发后无法撤回,有效期不宜太长
JWT泄露会被人冒用身份,为防止盗用,JWT应尽量使用https协议传输