- 服务描述
- 主要API
- /authorization/token/introspect 校验短token的有效性
- API /authorization/token 创建token
- API /authorization/token/revoke 撤销指定的token
- API /internal/token/revoke 撤销指定用户的token
- API /authorization/token/identity 查询id token
- API /authorization/secure-token 创建secure token
- API /internal/token/update 更新JWT参数
- API /authorization/validate 校验token?
- 没有这个接口
- API /authorization/authorize 创建授权码或创建token
- API /authorization/authorize/authcode-info 获取JWT详细信息
- API /authorization/register 注册client
- API /authorization/unregister 注销client?
- API /authorization/.well-know/jwks.json 获取公钥
- 主要业务流程
- 主要架构设计方案
- 主要数据库设计
- 遇到的问题和解决方案
- 优缺点和改进方案分析,业界对比
参考:
JWT - 专业剑 - 如何评价OCBC的token认证方案
服务描述
该服务主要负责鉴权token的管理,包括创建、续期、校验、撤销等。
因为所有的API的访问都需要通过gateway和token校验,所以该服务和接口的访问量非常大。
该服务采用了长短token的设计。
主要API
包括token的创建/authorization/token、续期/authorization/token、撤销/authorization/token/revoke、校验/authorization/introspect。
/authorization/token/introspect 校验短token的有效性
根据请求参数的短token和token type hint,校验该短token是否有效。
| 请求参数 | 描述 |
|---|---|
| token | 短token |
| tokenTypeHint | 枚举类型,token的类型,包括access_token,refresh_token |
| returnTokens | 可以为空,或者是希望返回的token类型,包括access_token,refresh_token,id_token |
| 响应参数 | 描述 |
|---|---|
| active | 短token的状态是否有效 |
| token | 长token具体值。如果active=false,则为空。 如果tokenTypeHint有值,该字段才会返回对应该token type的token的值。 |
| tokens | 长token的具体信息,IntrospectSubResponse对象列表类型,包括以下字段。 type 类型,包括access_token,refresh_token,id_token active,是否有效 token,长token的具体值 updatedTime,最后更新时间 reason,如果无效的原因,1-Revoked已撤销,2-Duplicate重复,3-Refreshed已刷新 |
| isRefreshable | 该token是否可以刷新 |
流程
如果tokenTypeHint为空,通过opToken,查询token表的有效记录。如果返回记录不为空,获取userTokenSession对象。
如果tokenTypeHint不为空,通过opToken和tokenTypeHint,查询内存userTokenSessionCache。
如果得到的userTokenSession对象为空,表示没有有效token。
通过opToken,查询token表的已删除记录,包括原因reason字段。
查询内存userTokenSession。
API /authorization/token 创建token
根据请求参数的grant type(authorization_code, refresh_token, token_exchange, resource_owner),生成并返回token。目前只支持authorization_code, refresh_token。
通过调用TokenCreator类的generate()方法创建token。
该方法调用JWTEncryptionService类的getRsaKey()方法获取RSAKey,getAuthPrivateKey()方法获取PrivateKey,再调用SignedJWT类的sign()方法创建token,包括access token和refresh token。
该方法通过调用JwtTokenUtil类的generateOpaqueToken()方法产生opaque token,实际是通过SecureRandom工具类产生随机字符串。
根据opaque token,access token和refresh token,创建UserTokenSession。
更新token表。
更新redis缓存。
authorization_code
场景:mobile端是API Key的拥有者,web端是资源请求者。
1. 先通过mobile端调用ms-auth/authorization/authorize接口,传参API Key,获得auth code。
2. mobile端传递auth code给web端。
3. web端调用ms-auth/authorization/token接口,传参auth code,获得一对短token(op-acc-token和op-ref-token)。
通过查询缓存或者auth_code表,获取可用auth code,设置状态为删除并更新表,返回auth code session。
校验auth code是否可用
如果是同组则撤销token
失效当前auth code
创建新token记录
refresh_token
场景:token续期。
请求传参一对当前短token(op-acc-token和op-ref-token),响应返回一对新的短token(op-acc-token和op-ref-token)
和/token/refresh接口什么区别?
校验当前token是否有效。撤销旧token。产生新token。包括以下步骤。
通过查询缓存或者token表,返回userTokenSession。
通过查询token_policy表,设置userTokenSession。
根据policy,刷新token。
撤销旧token,sts_cd='D',reason=3 - Refresh,ver_nbr+1。产生新token。
token_exchange 不支持
场景:第三方登录。
1. mobile端调用SingPass登录,SingPass校验用户名密码,返回SingPass JWT。
2. mobile端调用ms-authorization,传参SingPass JWT。
3. ms-authorization使用SingPass公钥,校验SingPass JWT,返回短token。
ms-customer-security/SingPass/login接口的作用?
3. ms-customer-security调用SingPass接口,传参授权码。SingPass校验成功。
4. ms-customer-security调用ms-auth/token接口,生成token并返回。
resource_owner 不支持
场景:最常见用法。
比如在登录成功后,调用ms-auth/token接口,传参API Key,获得一对短token(op-acc-token和op-ref-token)。
和authorization/authorize接口,传参request.responseType = RESOURCE_OWNER,有什么区别?不支持。
API /authorization/token/revoke 撤销指定的token
根据请求参数(token,tokenTypeHint,Reason),撤销token,更新token表和缓存。
tokenTypeHint,token类型包括op_acc_token,op_ref_token。
Reason包括1-REVOKED,2-DUPLICATED,3-REFRESHED。
更新原token记录(sts_cd='D',reason=请求参数Reason,ver_nbr+1)。
API /internal/token/revoke 撤销指定用户的token
revoke token based on user id and channel code.
步骤:
通过user id和channel code,查询token表。
如果记录不为空,软删除token表原记录。更新原token记录(sts_cd='D',reason=1 - REVOKED,ver_nbr+1)。
删除缓存的原记录。
API /authorization/token/identity 查询id token
通过请求参数的有效access token,返回id token。
通过请求头中的op_acc_token,查询缓存和token表,返回id_token字段。
API /authorization/secure-token 创建secure token
用于信任方(比如INB)为第三方(比如Robo Adviser)创建secure token(OCBC id token)。只支持request.grantType=TOKEN_EXCHANGE。
包括以下步骤。
查询token_policy表,通过source id和group code。
根据policy,校验id token是否有效。根据id token产生sub/subType。如果是同组则撤销旧token,sts_cd='D',reason=2 - DUPLICATED,ver_nbr+1。产生新的token。返回user token session。
API /internal/token/update 更新JWT参数
用于内部ms更新JWT内部的custom字段,包括amr,ial,custom,elevated_domain。
更新token表和缓存。
场景:用户登录成功后调用cust-auth/access-elevation/request和/validate,1FA升级到2FA,/validate成功后调用ms-auth/internal/token/update接口,更新JWT参数。
步骤:
校验请求头x-acc-op字段是否为空。
通过x-acc-op查询缓存或数据库,返回userTokenSession。
通过userTokenSession.accessToken获取JWT.custom。
如果updateTokenRequest.mode是SECURITY_CHECK_COMPLETED,移除custom.securityCheck字段。
如果是ELEVATION_CHECK_COMPLETED,移除custom.securityCheck字段,更新AMR、IAL、elevated_domain、device_info字段。
软删除原token记录(sts_cd='D',reason=null,ver_nbr+1)。
创建新的token记录,并保存DB。
更新缓存。
API /authorization/validate 校验token?
没有这个接口
API /authorization/authorize 创建授权码或创建token
根据responseType,创建并返回授权码authCode或者token。
校验client id。
查询token_policy表。
更新auth_code表。更新缓存。
request.responseType = CODE / RESOURCE_OWNER 分别代表类型:授权码,资源拥有者。
创建JWT的详细流程?
| 请求参数 | 描述 |
|---|---|
| API_KEY | |
| response_type | CODE: Auth Code flow,创建并返回Auth code。 RESOURCE_OWNER: 相当于创建并返回新token。 code-jwt, extended auth code flow to return authCode by given opaque token |
| client_id | |
| login_type | LEGAL_ID, ACCESS_CODE, MOBILE_NO |
| login_hint | access code, cif no or uuid |
| custom | JSON, org_id, cif_id, legal_id, legal_type |
| 响应参数 | 描述 |
|---|---|
| x-acc-op响应头 | 短token |
| x-ref-op响应头 | 短token |
| 响应体 | |
| authCode | 授权码,32位随机数字符串,第三方通过调用/token用来获得access token |
| state | |
| tokenType | 常量Bearer |
| expiresIn | token存续期,秒 |
v1和v2的区别?
v2版本只支持request.responseType=CODE_JWT。
API /authorization/authorize/authcode-info 获取JWT详细信息
根据auth code获取JWT详细信息。
查询缓存或auth_code表。
v1和v2版本的区别?
复用,没有区别。
API /authorization/register 注册client
通过请求参数和API key,user name,client type为依赖方注册。
在client表新增记录。
在token_policy表新增记录。
API /authorization/unregister 注销client?
API /authorization/.well-know/jwks.json 获取公钥
调用JWTEncryptionService类的getKid2PublicKeyMap()方法获取RSAKey列表。
通过配置文件key-store,加载RSA key,包括private key和public key。
主要业务流程
主要架构设计方案
主要数据库设计
token
token信息表,包括token取值,channel,group,用户ID,是否撤销,撤销原因。
| Field | Remark | Value |
|---|---|---|
| id | id | UUID |
| opAccessToken | op_acc_token | |
| accessToken | acc_token | |
| opRefreshToken | op_ref_token | |
| refreshToken | ref_token | |
| idToken | id_token | |
| channelCode | chnl_cd | |
| customerId | customer_Id | |
| groupCode | grp_cd | |
| revoked | revoked | boolean |
| expiresAt | exp_time | ZoneDateTime |
| sub | sub | |
| subType | sub_type | |
| reason | reason | Integer |
token_policy
token配置表,配置token的过期时间的配置。flyway脚本最常见的操作:新建和更新token_policy表。
| Field | Remark | Value |
|---|---|---|
| id | id | UUID |
grp_cd | group code | LLMS |
| chnl_cd | channel code | LLMS |
| auth_cd_exp_sec | auth code expiry | 30 |
| id_token_exp_sec | id token expiry | 600 - 10 min |
| acc_token_exp_sec | access token expiry | 600 - 10 min |
| ref_token_exp_sec | refresh token expiry | 900 - 15 min |
| max_ref_exp_sec | max refresh token expiry | 5940 - 99 min |
| ver_nbr | version | 0 |
| sts_cd | status code | A |
grp_cd + chnl_cd 唯一主键。
AuthCode
授权码
| Field | Remark | Value |
|---|---|---|
| id | id | UUID |
| groupCode | grp_cd | |
| channelCode | chnl_cd | |
| clientId | client_id | |
| customerId | customer_id | |
| code | ||
| authStartTime | auth_start_time | |
| nonce | ||
| loginHint | login_hint | |
| loginType | login_type | |
| scope | ||
| custom | custom | jsonb |
| amr | amr | jsonb |
| scopes | scopes | jsonb |
| ial | ||
| redirectUrl | redirect_url | |
| state | ||
| expiresAt | exp_time |
Client
注册ClientID,ClientType。
| Field | Remark | Value |
|---|---|---|
| id | id | UUID |
| clientName | client_name | |
| clientType | client_type | |
| clientSecret | client_secret | |
| grantType | grant_type | |
| scope | ||
| redirectUrl | redirect_url |
DeviceInfo
不是表
| Field | Remark | Value |
|---|---|---|
| fpt | ||
| tid | ||
| tsn | ||
| device |
遇到的问题和解决方案
优缺点和改进方案分析,业界对比
所有经过gateway的请求都需要调用ms-authorization,容易成为性能瓶颈。
日志太少。
