一、session
原理:其实就是server自己生成一个sessionId给client。client每次请求都带上,server在自己的内存里找有没有该sessionId对应的HttpSession对象,没有,就返回认证失败,如果有,就拿到用户状态信息,进行下一步操作。
PS:java存内存里,php存文件或者数据库里
存储的HttpSession对象(相关信息),会在超过默认时间没有交互之后,自动销毁,如果想优化的话,就使用js的window.onclose来监视浏览器的关闭动作,然后向服务器发送一个请求来关闭Session。但是常用的就是等它自动销毁
缺点:
- 如果用户量在一段时间内非常大, 那给服务器造成的内存压力非常大,占用非常大的内存。
- 如果做了负载均衡(多个机器),那么请求可能到了一台没有sessionID的机器,造成session丢失
- 存在安全问题,CSRF跨站伪造请求攻击,cookie可能被截获
session是基于cookie实现的,sessionId存在其他地方也可以,请求的时候在指定的位置带上就可以,给到服务端校验。session存在服务器,sessionId被cookie存在客户端
SessionID 是连接 Cookie 和 Session 的一道桥梁
二、Token
原理:是在用户输入账号密码校验通过的时候,服务器下发一个token,以后每次浏览器请求都带上token,服务器进行校验,成功了,就返回对应的数据信息。
1.access token
Access Token 的有效期比较短,当 Acesss Token 由于过期而失效时,使用 Refresh Token 就可以获取到新的 Token,如果 Refresh Token 也失效了,用户就只能重新登录了。
2、refresh token
Refresh Token 及过期时间是存储在服务器的数据库中,只有在申请新的 Acesss Token 时才会验证,不会对业务接口响应时间造成影响,也不需要向 Session 一样一直保持在内存中以应对大量的请求。
3、token的组成
header密文,payload密文,签名;header、 payload使用base64分别加密,再合起来,使用密钥和HS256加密生成签名,放后面
token = base64(header).base64(payload).HS256(密钥,base64(header).base64(payload))
4、token的校验
- 服务端使用原来的秘钥与密文(header密文+"."+payload密文)同样进行HS256运算,然后用生成的签名与token携带的签名进行对比,若一致说明token合法,不一致说明原文被修改。
- 判断是否过期,客户端通过用Base64解密第二部分(payload密文),可以知道荷载中授权时间,以及有效期。通过这个与当前时间对比发现token是否过期。
eyJhbGciOiJIUzI1NiJ9.
eyJnbG9iYWxfdXNlcl9pZCI6MTk3OSwiZ2xvYmFsX3VzZXJfbmFtZSI6Iui1teS4ueWugSIsImV4cCI6MTYyODQyNzY0N30.
HUPgAksi_nN3uc9UOlQ8_tvQQotNPEuLh3edlxgzZm8
三、JWT(Json Web Token)
- header (base64后的): { 'typ': 'JWT', 'alg': 'HS256' }
- payload (base64后的)
- secret
需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret(私钥)组合加密,然后就构成了jwt的第三部分
PS:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去
原理:jwt的token由3部分组成(如上),验证的过程是每次请求,获取到token,拿出前两部分解析,经过加盐私钥用header声明的加密算法生成签名,跟第三部分对比,一样就算验证通过,再拿到token中的用户信息,去进行下一步操作。不一样就返回认证失败
优点:
- 可扩展性好,不像session需要多机数据共享(内存或者redis)
- 无状态
缺点:
- 不安全,base64编码大家都知道
- 性能:如果payload的很大(可能有信息交换),经过base64编码后会非常大,cookie的4k内存可能存不下,就得放storage里,每次请求的时候都放header里,导致header比body还大,所以可能要比session的开销还大
- 一次性,无法废弃:我后来想在jwt的payload里加个字段或改一下值,所以签发了新的jwt,但是旧的还没过期,使用旧的jwt获取的是过期的payload。所以需要额外加个过期jwt的黑名单,避免使用过时的 4.续签:
第一种:每次请求都签发新的JWT,暴力且不优雅
第二种:需要在redis存上jwt的过期时间,每次请求,都刷新一下该jwt的过期时间,但是就是有状态的了,跟session差不多了。
适用场景:有效期短或者只有一次,比如邮箱链接账户激活
四、Token和JWT的区别
- Token:服务端验证客户端发送过来的 Token 时,还需要查询数据库获取用户信息,然后验证 Token 是否有效。
- JWT:用户的信息第二部分 Payload加密后和第三部分签名里都有,存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。就是服务端校验通过后,选择直接使用请求端给到的用户信息进行数据返回
五、SSO(Single Sign On)单点登录
意思就是把多于一个产品的用户登录逻辑抽离出来,达到只输入一次用户名和密码就能同时登录多个产品的效果
1、同域
登录
登出
区分系统:可以使用二级域名区分不同的系统,写入cookie在一级域名下,就比如【.songguo7.com】
2、不同域 CAS(Center Authentication Service)中心授权服务
SSO是一种设计,而CAS是实现它的方式其中之一,如果是同域名或者同父域可以使用session | token进行认证,但是跨域的情况下,多个产品不同域名,需要CAS实现认证。
登录
术语:
- TGT(T icket Grangting Ticket):存储在全局session中,集成用户信息和ST
- TGC(Ticket Grangting Cookie):存储在浏览器的cookie,就是TGT Session的标识(SessionID)可以理解为key,value是TGT
- ST(ServiceTicket):根据TGT生成,给到网站的
流程
- 我(浏览器)想看看A网站,但是A网站说我没登录
- 给我定向到认证中心,把A网站的地址作为参数放地址后面
-
SSO也说我没登录,因为我没有TGC,他里面也没有我的TGT,引导我到SSO的登录页面
-
我输入用户名+密码提交登录申请
-
认证中心验证成功,生成TGT,创建全局session,并把TGT存进去,创建TGC(存入浏览器cookie),重定向到A网站带着ST(令牌)放在请求地址后面作为参数
-
A网站拿到ST令牌去认证中心验证是不是它给的
-
验证通过,A网站拿着这个令牌创建了我与A网站的局部回话(session),返回受保护资源
-
我又想看看B网站,B网站看我没登录
-
B网站把自己的地址作为参数,跳到认证中心
-
认证中心看到有TGC,并且有效,就生成一个新的ST给B网站
-
B网站拿着令牌到认证中心验证
-
令牌有效,B网站也跟我建立了局部会话
-
返回受保护资源
注销
流程:
-
我在A网站发起注销申请
-
A网站拿到ST令牌,带着令牌向认证中心发起注销申请
-
认证中心校验令牌有效性
-
注销全局会话
-
向各个子系统发起注销请求
-
子系统接收认证中心注销请求,销毁局部会话
-
再访问就引导至登录界面
六、OAuth2.0(授权)
这就叫做 OAuth 2.0 协议。
你进行第三方授权时(文中的QQ),用户名和密码是不经过目标服务器的(文中的豆瓣),这保证了授权的安全性。
第三方授权服务器只给目标服务器返回有时效性的 code 和 token,目标服务器通过这个去第三方资源服务器,换取用户信息,这达成了拿到用户信息的目的。
所以总的来说,oauth 协议,就是由于三者(用户、目标、第三方)相互不信任,又想使用第三方服务器的授权功能,以及获取第三方服务器存储的用户信息,而产生的一个办法。
七、参考文档
-
查阅的资料很多,有点记不过来了,大家可以查缺补漏,指正错误~,没写上的,可以找到我加在参考文档里哈