跨域认证的问题
互联网服务离不开用户认证。一般流程是下面这样。
- 用户向服务器发送用户名和密码。
- 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
- 服务器向用户返回一个 session_id,写入用户的 Cookie。
- 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
- 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。
- 单机没有问题,若是服务集群,需要session数据共享
- 单点登录:
session数据持久化,实现持久层,做数据共享
不保存session,数据保存在客户端,每次请求携带,这就是JWT方案
JWT
JSON Web Token:是目前最流行的跨域认证解决方案,它由三部分组成头,部、载荷与签名。
header
{
'typ': 'JWT', //声明类型,这里是jwt
'alg': 'HS256' //声明加密的算法 通常直接使用 HMAC SHA256
}
base64加密后,构成了第一部分
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
playload
载荷就是存放有效信息的地方
定义一个payload:
{
"sub": "1234567890", //jwt所面向的用户
"name": "John Doe",
"admin": true
}
base64加密,得到Jwt的第二部分
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
signature
指定一个密钥(secret),这个密钥只有服务器才知道,不能泄露给用户。
HMAC SHA256签名算法
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
// 生成签名
var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
将三部分组成生成最终jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
- 签名的目的-防篡改
服务器应用在接受到JWT后,会首先对头部和载荷的内容用同一算法再次签名,进行验签。
如果服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,那么就说明这个Token的内容被别人动过的,我们应该拒绝这个Token
如何应用
一般是在请求头里加入Authorization,并加上Bearer标注:
fetch('api/user/1', {
headers: {
'Authorization': 'Bearer ' + token
}
})
流程如下:
- 客户端使用账户密码请求登录接口
- 登录成功后服务器使用签名密钥生成JWT ,然后返回JWT给客户端。
- 客户端再次向服务端请求其他接口时带上JWT
- 服务端接收到JWT后验证签名的有效性.对客户端做出相应的响应
JWT 的几个特点
- JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
- JWT 不加密的情况下,不能将秘密数据写入 JWT。
- JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
- JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
- JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
- 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
网友评论