sa-token-doc/oauth2/oauth2-openid.md
openid 是用户在某一 client 下的唯一标识,其有如下特点:
oauth2-client 在每次授权时可根据返回的 openid 值来确定用户身份。
框架默认的 openid 生成算法为:
md5(prefix + "_" + clientId + "_" + loginId);
其中的 prefix 前缀默认值为:openid_default_digest_prefix,你可以通过以下方式配置:
# sa-token配置
sa-token:
oauth2-server:
# 默认 openid 生成算法中使用的摘要前缀
openid-digest-prefix: xxxxxx
# 默认 openid 生成算法中使用的摘要前缀
sa-token.oauth2-server.openid-digest-prefix=xxxxxx
你也可以通过实现 SaOAuth2DataLoader 接口完全自定义 OpenId 生成算法:
/**
* Sa-Token OAuth2:自定义数据加载器
*/
@Component
public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
// 自定义 openid 生成算法
@Override
public String getOpenid(String clientId, Object loginId) {
// 此种写法代表使用框架默认算法生成 openid,真实环境建议改为从数据库查询
return SaOAuth2DataLoader.super.getOpenid(clientId, loginId);
}
}
正常来讲,openid 算法需要保证:
openid 一致。[必须]openid 不一致。[非常建议]openid 值。[建议]openid 值。[建议]openid 可以反查出对应的 clientId 和 loginId。[根据业务需求而定是否满足]框架内置的算法,可以满足 1和2,如果自定义了 sa-token.oauth2-server.openid-digest-prefix 配置,可以满足3。
如果自定义配置的 prefix 长度较短,或比较简单呈现规律性,则有客户端根据 clientId + loginId + openid 穷举爆破出 prefix 的风险,
从而获得提前计算彩虹表来推测出其它 clientId、loginId 对应 openid 值的能力。
如果自定义的 prefix 前缀比较复杂,让客户端无法爆破,则可以满足4。但依然无法满足5。
所以 openid 算法的最优解,应该是 oauth2-server 采用随机字符串作为 openid,然后自建数据库表来维护其映射关系,这样可以同时满足12345。
表结构参考如下:
UnionId 的特点与 OpenId 几乎一致:同一用户在不同 client 里的 UnionId 值是不同的,除非这些应用属于同一主体。
例如:甲公司申请了应用A、应用B、应用C,乙公司申请了应用D、应用F,那么用户张三:
那么 Sa-Token 框架是如何识别到某两个应用是否为同一主体的呢?这就需要你在注册应用时指定 subjectId 属性了:
/**
* Sa-Token OAuth2:自定义数据加载器
*/
@Component
public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
// 根据 clientId 获取 Client 信息
@Override
public SaClientModel getClientModel(String clientId) {
// 此为模拟数据,真实环境需要从数据库查询
if("1001".equals(clientId)) {
return new SaClientModel()
.setClientId("xxxx")
.setClientSecret("xxxx")
.setSubjectId("1000001") // ⚠️ 关键代码:主体 id (可选)
// ....
;
}
return null;
}
}
subjectId 代表此应用的拥有者,相同 subjectId 值的应用将被识别为同一主体,在授权中返回的 unionid 值也将一致。
框架默认的 unionid 生成算法为:
md5(prefix + "_" + subjectId + "_" + loginId);
其中的 prefix 前缀默认值为:unionid_default_digest_prefix,你可以通过以下方式配置:
# sa-token配置
sa-token:
oauth2-server:
# 默认 unionid 生成算法中使用的摘要前缀
unionid-digest-prefix: xxxxxx
# 默认 unionid 生成算法中使用的摘要前缀
sa-token.oauth2-server.unionid-digest-prefix=xxxxxx
你也可以通过实现 SaOAuth2DataLoader 接口完全自定义 UnionId 生成算法:
/**
* Sa-Token OAuth2:自定义数据加载器
*/
@Component
public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
// 自定义 unionid 生成算法
@Override
public String getUnionid(String subjectId, Object loginId) {
// 此种写法代表使用框架默认算法生成 unionid,真实环境建议改为从数据库查询
return SaOAuth2DataLoader.super.getUnionid(subjectId, loginId);
}
}
unionid 算法要求与 openid 基本一致,可参考上述 openid 算法要求介绍,此处暂不赘述。
| 类型 | 概念 |
|---|---|
| userid | 在 oauth2-server 端的用户,其唯一标识 |
| clientid | 第三方公司在 oauth2-server 开放平台申请的应用,其唯一标识 |
| openid | 用户在某个应用下的唯一标识 |
| unionid | 用户在某一组应用下的唯一标识 (按照主体id分组) |