Loading... ## 登录注销基本流程 **登录** 在客户端请求登录时,服务器端用户及其他信息新建`session`,并在返回响应时为客户端浏览器设置`cookies` 浏览器接收到`cookies`将其保存到本地 之后每次请求,会携带`cookies`请求服务器端 服务器端接收`cookies`,根据`cookies`找到`session`,匹配是否有效。 有效则正常返回响应,无效则跳转到错误信息页面或者其他操作 > 1. 用户向服务器发送用户名和密码。 > 2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。 > 3. 服务器向用户返回一个 session_id,写入用户的 Cookie。 > 4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。 > 5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。 **注销** 服务器端的`session`会有失效时间,超过这个时间就会被删除以节省存储空间 当用户主动点击注销时,则是请求服务器端将此用户对应的`session`删除 ## 会话Cookie和持久Cookie > 从表面意思来说,会话Cookie就是把Cookie放在浏览器内存里,浏览器在关闭之后该Cookie即失效;持久Cookie则会保存到客户端的硬盘中,下次还可以继续使用,用于长久保持用户登录状态。 这是由`cookie`的`Max Age`或`Expires`字段决定其过期时间 ## 额外补充 JWT > 上方模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。 > > 举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现? > > 一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。 > > 另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。 JWT 全称 Json Web Token ### JWT原理 服务器认证通过后,生产一个JSON对象返回给用户 <pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" cid="n195" mdtype="fences"> <span role="presentation"><span cm-text=""></span></span><br/> <span role="presentation">{</span><br/> <span role="presentation"> "姓名": "张三",</span><br/> <span role="presentation"> "角色": "管理员",</span><br/> <span role="presentation"> "到期时间": "2018年7月1日0点0分"</span><br/> <span role="presentation">}</span></pre> 以后,用户与服务器端的交互都将发送这个`json`给服务器端,服务器端完全依靠这个`json`判定用户,为了防止`json`被篡改会对此进行加密。 服务器端就不在保存任何`session`数据,此时服务器变成了无状态,从而比较容易实现扩展。 ### JWT的数据结构  它是一个很长的字符串,中间使用`.`分割成三部分,三部分依次如下: * Header(头部) * Payload(负载) * Signture(签名) #### Header `Header`部分是一个Json对象,描述JWT的元数据 <pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" cid="n212" mdtype="fences"> <span role="presentation">{</span><br/> <span role="presentation"> "alg": "HS256",</span><br/> <span role="presentation"> "typ": "JWT"</span><br/> <span role="presentation">}</span></pre> `alg`: 全称algorithm(算法),表示签名所实现的算法,默认是 HMAC SHA256(写成 HS256) `typ`:type属性表示令牌(token)的类型,JWT令牌统一写`JWT` #### Payload `Payload`包含了用户的基本信息以及JWT官方规定的7个字段(供选择) 官方规定的7个字段: * iss (issuer):签发人 * exp (expiration time):过期时间 * sub (subject):主题 * aud (audience):受众 * nbf (Not Before):生效时间 * iat (Issued At):签发时间 * jti (JWT ID):编号 自定义字段:(可以包含不敏感的用户信息) <pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" cid="n235" mdtype="fences"> <span role="presentation">{</span><br/> <span role="presentation"> "sub": "1234567890",</span><br/> <span role="presentation"> "name": "John Doe",</span><br/> <span role="presentation"> "admin": true</span><br/> <span role="presentation">}</span></pre> #### Signtrue `Signtrue`对前面两部分的签名,防止数据被篡改 首先,需要指定一个秘钥(secret),这个秘钥只有服务器知道,不能泄露。然后使用`Header`指定的签名算法,按照下面的公式生成JWT <pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" cid="n240" mdtype="fences"> <span role="presentation">HMACSHA256(</span><br/> <span role="presentation"> base64UrlEncode(header) + "." +</span><br/> <span role="presentation"> base64UrlEncode(payload),</span><br/> <span role="presentation"> secret)</span></pre> #### Base64URL `Base64URL`与`Base64`基本类似,但是有一些细节不同。 JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符`+`、`/`和`=`,在 URL 里面有特殊含义,所以要被替换掉:`=`被省略、`+`替换成`-`,`/`替换成`_` 。这就是 Base64URL 算法。 ## 参考文章 [Session和Cookies的基本原理](https://mp.weixin.qq.com/s?__biz=MzIzNzA4NDk3Nw==&mid=2457735603&idx=1&sn=2ac4107c695c7b45a58d8e66d4161a3f&chksm=ff44b9edc83330fbb125b612cea0b06a4ea31031c90030a3f9da3529fc6fd4e8422a972e31f8&mpshare=1&scene=23&srcid=0824ZzcxGlf3qOVYYMggivT6&sharer_sharetime=1598271600739&sharer_shareid=00bca55feaecb55710fa0a163922966c#rd) [JSON Web Token 入门教程](http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html) Last modification:August 25th, 2020 at 11:42 am © 允许规范转载