目前我们常用的鉴权有四种:

纯cookie验证

步骤分解
-
浏览器首次登录,服务器收到请求后去数据库校验用户名及密码
-
校验通过后,从数据库查询对应的用户信息
-
把非重要信息(如密码,邮箱等)通过响应体
set-cookie存入到浏览器中 -
浏览器下次请求接口,自动携带
cookie信息在请求体中,其中包含了用户的信息(如username) -
服务器拿到请求体中的
cookie,如果包含username等用户信息,则校验通过
session+cookie

步骤分解
-
浏览器首次登录,服务器收到请求后去数据库校验用户名及密码
-
校验通过后,从数据库查询对应的用户信息
-
在服务器进程中创建
session,把用户信息保存起来 -
设置响应体(
Set-Cookie),把sessionId(一般是userId,因为userId比直接暴露username更安全)返回 -
浏览器下次请求接口,自动携带
cookie信息在请求体中,其中包含了sessionId -
服务器拿到请求体中的
sessionId,判断sessionId对应的是哪个用户 -
查询到对应用户后,执行后续操作。反之,权限校验失败
Token

步骤分解
-
浏览器首次登录,服务器收到请求后去数据库校验用户名及密码
-
校验通过后,从数据库查询对应的用户信息
-
服务器将用户信息通过密钥生成令牌(
Access Token),并返回给浏览器 -
浏览器拿到令牌之后,可以保存到
cookie或者localStorage、sessionStorage中 -
浏览器下次请求接口,将
Access Token放到请求头header中 -
服务端拿到请求头的
token,然后通过密钥解密,校验通过后执行后续操作。反之,权限校验失败
优缺点
- 优点:
无状态可以减轻服务器压力,减少频繁查询数据库- 安全性高,token解密密钥只有服务端知道,客户端无法解密
- 缺点:
- token过期时间短,需要refresh-token配合使用,refresh token是在access token过期时重新获取token的
- refresh token也有过期时间,会增加数据库查询次数
JWT(Json-web-tokens)

完成的JWT token长什么样?
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhIiwiaWF0IjoxNTUxOTUxOTk4fQ.2jf3kl_uKWRkwjOP6uQRJFqMlwSABcgqqcJofFH5XCo
如何生成的?
它由三部分组成:Header(头部)、Payload(负载)、Signature(签名)。
-
Header部分是一个JSON对象,描述JWT的元数据。一般描述信息为该Token的加密算法以及Token的类型。{"alg": "HS256","typ": "JWT"}的意思就是,该token使用HS256加密,token类型是JWT。这个部分基本相当于明文,它将这个JSON对象做了一个Base64转码,变成一个字符串。Base64编码解码是有算法的,解码过程是可逆的。头部信息默认携带着两个字段。 -
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。有7个官方字段,还可以在这个部分定义私有字段。一般存放用户名、用户身份以及一些JWT的描述字段。它也只是做了一个Base64编码,因此肯定不能在其中存放秘密信息,比如说登录密码之类的。 -
Signature是对前面两个部分的签名,防止数据篡改,如果前面两段信息被人修改了发送给服务器端,此时服务器端是可利用签名来验证信息的正确性的。签名需要密钥,密钥是服务器端保存的,用户不知道。算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
步骤分解
-
浏览器首次登录,服务器收到请求后去数据库校验用户名及密码
-
校验通过后,从数据库查询对应的用户信息
-
服务器将用户信息生成
jwt,并返回给客户端 -
浏览器拿到
jwt之后,可以保存到cookie或者localStorage、sessionStorage中 -
浏览器下次请求接口,将
jwt放到请求头header中(默认格式Authorization: Bearer jwt) -
服务端检查
jwt的签名信息,从jwt中获取用户信息,并执行后续操作。反之,权限校验失败
优缺点
- 优点:
- 安全性高
- 解决服务器压力,减少服务器查询次数
- 缺点:
- jwt需要加密
前端代码实现
// 拦截请求
request.interceptors.request.use((config)=>{
let token = localStorage.getItem('token')
config.headers.Authorization = token
return config
})
// 拦截响应
request.interceptors.response.use((response)=>{
if(response.headers.authorization){
localStorage.setItem('token',response.headers.authorization)
}
return response
},function(err){
if(err.response.status == 401){
router.push('/login')
}
return Promise.reject(err)
})