1. jwt 原理

一个JWT实际上就是一个字符串,它由三部分组成,头部载荷签名

1.1 header

  1. {
  2. "typ":"JWT",
  3. "alg":"HS256"
  4. }

这是头部的明文内容,第一部分说明他是一个jwt,第二部分则指出签名算法用的是HS256算法(对称加密),HR256非对称加密
将这个头部进行BASE64编码,编码后形成头部:

  1. eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

1.2 payload

载荷就是存放有效信息的地方,有效信息包含三个部分:
(1)标准中注册的声明(建议但不强制使用)

  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

(2)公共的声明 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息. 但不建议添加敏感信息,因为该部分在客户端可解密.
(3)私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

  1. {
  2. "sub":"1234567890",
  3. "name":"tengshe789",
  4. "admin": true
  5. }

上面就是一个简单的载荷的明文,接下来使用base64加密:

  1. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

1.3 签证(signature)

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第 三部分。

  1. TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

1.4 合成token

将header、payload、signature 通过. 号连接

  1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

1.5 JWT 优势劣势

  • 优势:
    • 跨域,不依赖cookie
    • 适合多节点,单点登录等应用场景
  • 劣势:
    • 注销、修改密码,token仍然有效
      • 解决方案: token 存入redis,数据库,如果需要让某个 token 失效就直接从 redis 中删除这个 token 即可。
    • token 续期:
      • 解决方案:每次校验自动续期。
    • base64体积大
      • 解决方案:payload 只存储主要信息。


2. Oauth2介绍

OAuth 2.0 是一种授权机制,主要用来颁发令牌(token),主要用来实现第三方登录。

2.1 角色

OAuth定义了四种角色:

  • 资源所有者
    能够许可受保护资源访问权限的实体。当资源所有者是个人时,它作为最终用户被提及。
  • 资源服务器
    托管受保护资源的服务器,能够接收和响应使用访问令牌对受保护资源的请求。
  • 客户端
    使用资源所有者的授权代表资源所有者发起对受保护资源的请求的应用程序。术语“客户端”并非特指任何特定的的实现特点(例如:应用程序是否在服务器、台式机或其他设备上执行)。
  • 授权服务器
    在成功验证资源所有者且获得授权后颁发访问令牌给客户端的服务器。
    授权服务器和资源服务器之间的交互超出了本规范的范围。授权服务器可以和资源服务器是同一台服务器,也可以是分离的个体。一个授权服务器可以颁发被多个资源服务器接受的访问令牌。

    2.2 流程

    1. +--------+ +---------------+
    2. | |--(A)- Authorization Request ->| Resource |
    3. | | | Owner |
    4. | |<-(B)-- Authorization Grant ---| |
    5. | | +---------------+
    6. | |
    7. | | +---------------+
    8. | |--(C)-- Authorization Grant -->| Authorization |
    9. | Client | | Server |
    10. | |<-(D)----- Access Token -------| |
    11. | | +---------------+
    12. | |
    13. | | +---------------+
    14. | |--(E)----- Access Token ------>| Resource |
    15. | | | Server |
    16. | |<-(F)--- Protected Resource ---| |
    17. +--------+ +---------------+
    图1中所示的抽象OAuth 2.0流程描述了四个角色之间的交互,包括以下步骤:
    (A)客户端向从资源所有者请求授权。授权请求可以直接向资源所有者发起(如图所示),或者更可取的是通过作为中介的授权服务器间接发起。
    (B)客户端收到授权许可,这是一个代表资源所有者的授权的凭据,使用本规范中定义的四种许可类型之一或 者使用扩展许可类型表示。授权许可类型取决于客户端请求授权所使用的方式以及授权服务器支持的类型。
    (C)客户端与授权服务器进行身份认证并出示授权许可请求访问令牌。
    (D)授权服务器验证客户端身份并验证授权许可,若有效则颁发访问令牌。
    (E)客户端从资源服务器请求受保护资源并出示访问令牌进行身份验证。
    (F)资源服务器验证访问令牌,若有效则满足该请求。
    客户端用于从资源所有者获得授权许可(步骤(A)和(B)所示)的更好方法是使用授权服务器作为中介,如 4.1节图3所示。

    3. SSO 单点登录

    3.1 SSO单点登录与 oauth2关系与区别

  1. sso 单点登录 是基于 oauth2的令牌机制。
  2. 从信任角度来看。OAuth2.0授权服务端和第三方客户端不属于一个互相信任的应用群(通常都不是同一个公司提供的服务),第三方客户端的用户不属于OAuth2.0授权服务端的官方用户;而单点登录的服务端和接入的客户端都在一个互相信任的应用群(通常是同一个公司提供的服务),各个子系统的用户属于单点登录服务端的官方用户。
  3. 从资源角度来看。OAuth2.0授权主要是让用户自行决定——“我”在OAuth2.0服务提供方的个人资源是否允许第三方应用访问;而单点登录的资源都在客户端这边,单点登录的服务端主要用于登录,以及管理用户在各个子系统的权限信息。
  4. 从流程角度来看。OAuth2.0授权的时候,第三方客户端需要拿预先“商量”好的密码去获取Access Token;而单点登录则不需要。

    3.2 单点登录服务端的设计

    image.png

    3.2.1 单点登录服务端

  • client请求单点登录服务端,获取Access Token
  • client因为不能判断给它的Access Token是单点登录服务端返回还是用户伪造,所以需要再次请求单点登录服务端,校验Access Token是否有效,如果有效则返回用户基本信息以及相应的用户在client上所属的角色、权限等信息

表结构:

  • sso_client_details :
    • client_name:子系统的名称
    • redirect_url:获取Access Token成功后的回调URL
    • logout_url:用户在子系统的注销URL(用户登录状态可以分为:全局登录——在单点登录服务端的登录状态;局部登录——在子系统的登录状态,注销的时候需要同时注销用户在单点登录服务端和应用子系统的登录状态)
  • sso_access_token :
    • access_tokenAccess Token字段
    • user_id:表明是哪个用户登录
    • client_id:表明是在哪个子系统登录
    • expires_in:过期时间戳,表明这个Token在哪一天过期
  • sso_refresh_token :
    • refresh_tokenRefresh Token字段
    • token_id:它对应的sso_access_token表的记录
    • expires_in:过期时间戳

主要接口:
获取token: /sso/token?redirect_uri=http://192.168.197.130:6080/login
校验token: /sso/verify?access_token=11.ad51132688b5be3f476592356c78aef71d235f07
刷新token: /sso/refreshToken
登录注销接口:

  1. 用户在应用子系统请求注销登录;
  2. 用户在应用子系统注销完成后,应用子系统后台请求单点登录服务端的注销接口;
  3. 单点登录服务端的注销接口根据用户的Token在数据库中查询当前用户登录的所有应用子系统的注销接口,然后依次调用注销即可。

3.2.2 单点登录子系统设计

登录接口:调用远程登录服务器接口,校验token,保存用户信息到session
注销接口:用户在子系统注销,远程调用单点登录服务器注销接口;

4. RABC 权限系统

JWT认证 %26 Oauth2 授权 %26 RBAC权限管理 - 图2

  • 用户与角色之间是多对多的关系,一个用户有多个角色,一个角色包含多个用户
  • 角色与权限之间是多对多关系,一个角色有多种权限,一个权限可以属于多个角色

上图中: