了解为啥要登录

我们知道HTTP是无状态的协议,就是在两次请求之间服务器不会保存任何的数据。所以,登录就是用某种方法让服务器在多次请求之间能够识别出你,而不是每次请求的时候都带上用户名和密码这样的信息。从登录成功到登出的这个过程,服务器一直维护了一个可以识别出用户信息的数据结构,广义上来说,这个过程就叫做session,也就是保持了一个会话。


常见的两种登录方式:

服务端session + 客户端sessionId

用一张图来说明整个过程:

前端如何获取session并向后端发包 前端如何使用session_服务器端

1.客户端访问login接口,post服务器username、password等注册用的信息,服务器收到后校验信息,正确后会在服务器端存储一个sessionId和session的映射关系

前端如何获取session并向后端发包 前端如何使用session_服务器端_02

2.服务器端返回response,并且将sessionId以set-cookie的方式发送到客户端,这样sessionId就存在了客户端。把sessionId存到cookie不是强制的方案,而是一般都这么做,这样在发送请求时,会自动带上cookie,省去了手动添加的过程。

3.客户端发送非登录请求时,服务端就能通过cookie中的sessionId找到对应的session来知道这次请求是谁发的

 

token

前面说到sessionId的方式本质是把用户状态信息维护在server端,token的方式就是把用户的状态信息加密成一串token传给前端,然后每次发请求时把token带上,传回给服务器端;服务器端收到请求之后,解析token并且验证相关信息

跟第一种登录方式最本质的区别是:通过解析token的计算时间换取了session的存储空间

业界通用的加密方式是jwt,大概像下面这样:

前端如何获取session并向后端发包 前端如何使用session_服务器端_03

由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 <token>

这样可以解决cookie跨域问题,不过放哪里还是根据业务需求来定。


两种方案存在的问题

session方式

1.session方式由于会在服务器端维护session信息,单机还好说,如果是多机的话,服务器之间需要同步session信息,服务横向扩展不方便

2.session数量随着登录用户的增多而增多,存储会增加很多

3.session+cookie里面存sessionId的方式可能会有csrf攻击的问题

jwt方式

1.JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑

2.JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证