账户体系(SSO, JWT与OAuth)
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来说,可能会是个问题
-
参考:
OAuth
-
OAuth是让第三方应用不需要用户名密码读取用户数据的一个认证过程
- 但通过oauth方式授权,第三方应用可以凭借他手中的授权"凭证" (access token) 做一些他想做的事情,比如直接帮你关注某个微博账号
-
第三方登录授权流程(以GitHub登录A网站为例)
-
登陆前
- A网站向GitHub 登记自己身份
- GitHub返回client ID和client secret
-
登陆时
- GitHub要求用户登录并询问是否允许授权A网站
- 用户同意,GitHub 就会重定向回 A 网站注册的跳转网址,同时发回一个授权码(code)
- A 网站使用授权码,向 GitHub 请求令牌
- 需要提供client_id, client_secret ,code
- 令牌有过期时间和权限范围
- A 网站使用Github返回的令牌(accessToken),向 GitHub 请求用户数据
-
为什么第一次要返回code,而不是token?
-
原因1:
- A网址第一次请求GitHub时不会带上 client_secret,因为无法证明该网站就是GitHub
- 而GitHub为了验证A网址合法性,需要在获得client_secret后才发放token
-
原因2:
- 授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成(HTTPS)
- 这样的前后端分离,可以避免令牌泄漏
- 如果是纯前端应用,则直接范围token
- 这样很不安全的,因此只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短
- 授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成(HTTPS)
-
原因1:
-
为什么要返回令牌而不是直接返回用户数据?
- 因为A网址可能一段时间后又需要请求该数据或者需要请求其他数据,此时可以复用令牌,而不用再次鉴权
-
登陆前