SSO
- 单点登录(SSO: Single Sign-On)
- 一套公用的用户体系,用户只要登陆之后,就能够访问所有的系统
- 比如登录了淘宝就不用再登录天猫了
- 一套公用的用户体系,用户只要登陆之后,就能够访问所有的系统
- 也用于解决跨域问题
- 参考
JWT
-
JWT就像一个临时的用户凭证,代替了用户名和密码组合
-
JWT 的目的不是为了隐藏或者保密数据,而是为了确保数据确实来自被授权的人创建的(不被篡改)
-
优点
- 为了确认它是否有效,我们只需要看JWT本身的内容,而不需要借助于第三方服务或者在多个请求之间将其保存在内存中(session)
- 因为它本身携带了信息验证码MAC(Message Authentication Code)
- 为了确认它是否有效,我们只需要看JWT本身的内容,而不需要借助于第三方服务或者在多个请求之间将其保存在内存中(session)
-
缺点
- 服务后台无法拒绝携带JWT的请求(如踢除用户)
- 服务器端没法统计多少个人登录了,一个人登录了多少次,登陆了什么设备
- 无法很好的控制payload的数据量
- 应该只把认证的相关信息放到payload里。但实际上,开发人员往往会误用,把几乎所有和user相关的数据都放到payload里
- 会极大的损耗带宽和IO性能,因为每次请求都必须把全量的JWT都带着
-
JWT一般用于身份验证,不用于储存会话状态(代替cookie)
-
它是 JSON 结构的 token,由三部分组成:header,payload,signature
- 格式:
Base64(Header) + "." + Base64(Payload) + "." + $Signature
- header
- JSON对象,用于描述元信息,例如产生 signature 的算法
- payload
- 用于携带希望向服务端传递的信息
- 由于payload不加密,建议只在其中保存非敏感的用于身份验证的数据
- signature 用于校验合法性
- 利用认证服务器的密钥进行签名
- 格式:
HS256(Base64(Header) + "." + Base64(Payload), secretKey)
- 也不一定要使用HS256加密
- 格式:
-
客户端发送方式
- 你可以把JWT放在 Cookie 里面自动发送,但是这样不能跨域
- 更好的做法是放在 HTTP 请求的头信息Authorization字段里面
Authorization: Bearer<token>
- 或者放在 POST 请求的数据体里面
-
认证流程
- 用户向认证服务器提交用户名和密码
- 认证服务器也可以和应用服务器部署在一起,但往往是独立的居多
- 认证服务器校验用户名和密码组合,然后创建一个JWT token,发送给客户端
- token的Payload里面包含用户的身份信息,以及过期时间戳
- 使用私钥对Header和Payload进行签名
- 只有认证服务器拥有私钥
- 客户端之后的每个HTTP请求中附带着发送给应用服务器
- 应用服务器使用公钥检查JWT签名,确认Payload确实是由密钥拥有者签过名的
- 用户向认证服务器提交用户名和密码
-
为什么不直接对payload进行加密
- RSA加密过程比较慢,对于数据比较大的Payload来说,可能会是个问题
- RSA加密过程比较慢,对于数据比较大的Payload来说,可能会是个问题
-
参考:
CAS
- CAS Server起到了一个认证中心的作用,其实所有登录态都是保持在其所在域名下,所有其他域名下的登录态都是基于CAS域名下ticket校验获得的
- ticket只能使用一次,且有过期时间
- CAS方式不方便持久化数据,session过期或是清除后需要再次获取授权
- 登录流程
- Client发起一个A域名(业务域名)下对Server资源的请求;
- Server对请求未通过登录校验,返回302请求使Client跳转至B域名,此时通过query参数带上A域名回调地址;
- Client在B域名(CAS Server域名)下登录校验,同时也会对query参数中A域名回调地址进行校验域名。通过校验后,CAS Server返回302请求使Client跳转至A域名回调地址,并再query参数中带上ticket参数;
- Server获取到ticket参数后再请求CAS Server接口进行登录校验;
- 可以将登录状态信息存储在Session Server统一管理,进行缓存,减少请求;
- Server将资源返回Client;
- 登出流程
- Client访问A域名一个指定登出路径,例如
/api/logout
- Server接收到指定路径请求后,清除Session Server中的登录状态
- Server返回302,使Client重定向至B域名指定路径,CAS Server接收到请求后,清除全部该用户登录状态
- Client访问A域名一个指定登出路径,例如
OAuth2
- OAuth2是让第三方应用不需要用户名密码读取指定用户数据的一个认证过程
- 如果权限控制不好,通过oauth方式授权,第三方应用可以凭借他手中的授权"凭证" (access token) 做一些他想做的事情,比如直接帮你关注某个微博账号
- 第三方登录授权流程(以GitHub账号登录A网站为例)
- 登陆前
- A网站向GitHub 登记自己身份
- https://github.com/settings/applications/new
- 需要提供主页和回调网址
- GitHub返回client ID和client secret
- A网站向GitHub 登记自己身份
- 登陆时
- A网站跳转到GitHub认证网页
- 同时带上client ID, 回调网址和授权范围等信息
- GitHub要求用户登录并询问是否允许授权A网站
- 用户同意,GitHub 就会重定向回 A 网站注册的跳转网址,同时附上一个授权码(code)
- 该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝
- 该码与客户端ID和重定向URI,是一一对应关系
- A 网站使用授权码,向 GitHub 请求令牌
- 需要提供client_id, client_secret ,code
- 令牌有过期时间和权限范围
- A 网站使用Github返回的令牌(accessToken),向 GitHub 请求用户数据
- 这一步是在客户端的后台的服务器上完成的
- A网站的后端将 token 存储下来,同时将用户可以公开的信息通过 cookie、JWT 等形式返回给前端
- A网站跳转到GitHub认证网页
- 为什么第一次要返回code,而不是token?
- 授权码通过前端传送给用户,在由用户通过前端给给A网站,容易造成令牌泄露
- A网站与GitHub的交互是在后端通过HTTPS安全连接交互的
- 这样的前后端分离,可以避免令牌泄漏
- 即使黑客截获了 code,他没有那串预先商量好的client_secret,也是无法获取 token 的
- 如果是纯前端应用,则直接返回token
- 这样很不安全的,因此只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短
- 为什么要返回令牌而不是直接返回用户数据?
- 因为A网址可能一段时间后又需要请求该数据或者需要请求其他数据,此时可以复用令牌,而不用再次鉴权
- 登陆前
CAS与OAuth2区别
(A为用户,B为要登录的应用,C为CAS服务,D为oauth2 服务提供者)
- 保护资源的位置不同
- CAS 的单点登录,保障的是B资源的安全
- 资源在 D这一方,保障的是D资源的安全,B是想索取D的用户的资源
- B要获取的信息不同
- 对于CAS,B要获取的最终信息是,这个用户到底有没有权限访问我的资源
- 对于OAuth2, B获取的最终信息是,D的用户资源到底能不能让B访问
- 获取信息的流程不同
- CAS 通过 token 校验的时候,不需要传预先设定的secret
- OAuth 通过 code 换取 token 的时候,需要传secret
- 支持的功能不同
- CAS只用于身份识别和认证
- OAuth除了支持身份识别和认证,也支持授授权