了解为啥要登录
我们知道HTTP是无状态的协议,就是在两次请求之间服务器不会保存任何的数据。所以,登录就是用某种方法让服务器在多次请求之间能够识别出你,而不是每次请求的时候都带上用户名和密码这样的信息。从登录成功到登出的这个过程,服务器一直维护了一个可以识别出用户信息的数据结构,广义上来说,这个过程就叫做session,也就是保持了一个会话。
常见的两种登录方式:
服务端session + 客户端sessionId
用一张图来说明整个过程:
1.客户端访问login接口,post服务器username、password等注册用的信息,服务器收到后校验信息,正确后会在服务器端存储一个sessionId和session的映射关系
2.服务器端返回response,并且将sessionId以set-cookie的方式发送到客户端,这样sessionId就存在了客户端。把sessionId存到cookie不是强制的方案,而是一般都这么做,这样在发送请求时,会自动带上cookie,省去了手动添加的过程。
3.客户端发送非登录请求时,服务端就能通过cookie中的sessionId找到对应的session来知道这次请求是谁发的
token
前面说到sessionId的方式本质是把用户状态信息维护在server端,token的方式就是把用户的状态信息加密成一串token传给前端,然后每次发请求时把token带上,传回给服务器端;服务器端收到请求之后,解析token并且验证相关信息
跟第一种登录方式最本质的区别是:通过解析token的计算时间换取了session的存储空间
业界通用的加密方式是jwt,大概像下面这样:
由header(头部)、payloader(载体)、signature(签名)三个部分组成:
Header部分是一个JSON对象,描述jwt的元数据
{
"alg": "HS256",
"typ": "JWT"
}
alg属性表示签名的算法,typ表示令牌(token)的类型
Payload部分也是JSON对象,存放实际要传输的数据。
JWT规定了7个官方字段供选用:
{
"iss": "签发人",
"exp": "过期时间",
"sub": "主题",
"aud": "受众",
"nbf": "生效时间",
"iat": "签发时间",
"jti": "编号"
}
自定义私有字段:
{
"name": "admin",
"password": "asdasdasd"
}
Signature部分是对前两部分的签名,防止数据篡改
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256)
总之,最后定的jwt = base64url(header) + "." + base64url(payload) + "." + signature
jwt可以放在response中返回,也可以放在cookie中返回,官方推荐放在HTTP的 header中
Authorization: Bearer
这样可以解决cookie跨域问题,不过放哪里还是根据业务需求来定。
两种方案存在的问题
session方式
1.session方式由于会在服务器端维护session信息,单机还好说,如果是多机的话,服务器之间需要同步session信息,服务横向扩展不方便
2.session数量随着登录用户的增多而增多,存储会增加很多
3.session+cookie里面存sessionId的方式可能会有csrf攻击的问题
jwt方式
1.JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑
2.JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证
转自知乎网友:https://zhuanlan.zhihu.com/p/62336927