基于Security实现OIDC单点登录的详细流程
⽬录
⼀、说明
⼆、OIDC核⼼概念三、什么是IDToken
3.1.与JWT的AccessToken区别3.2.与UserInfo端点的区别四、OIDC单点登录流程五、SpringSecurity实现六、完整的demo下载地址
⼀、说明
本⽂主要是给⼤家介绍 OIDC 的核⼼概念以及如何通过对 Spring Security 的授权码模式进⾏扩展来实现 OIDC 的单点登录。
OIDC 是 OpenID Connect 的简称,OIDC=(Identity, Authentication) + OAuth 2.0。它在 OAuth2 上构建了⼀个⾝份层,是⼀个基于 OAuth2 协议的⾝份认证标准协议。我们都知道 OAuth2 是⼀个授权协议,
它⽆法提供完善的⾝份认证功能,OIDC 使⽤ OAuth2 的授权服务器来为第三⽅客户端提供⽤户的⾝份认证,并把对应的⾝份认证信息传递给客户端,且完全兼容 OAuth2。PS:理解 OIDC 的前提是需要理解 OAuth2,如果对 OAuth2 的单点登录的原理和流程还不太了解的可以看我之前的⽂章《》
⼆、OIDC核⼼概念
OAuth2 提供了 Access Token 来解决授权第三⽅ 客户端 访问受保护资源的问题;OIDC 在这个基础上提供了 ID Token 来解决第三⽅客户端标识⽤户⾝份认证的问题。OIDC 的核⼼在于 OAuth2 的授权流程中,⼀并提供⽤户的⾝份认证信息 ID Token 给到第三⽅ 客户端,ID Token 使⽤ JWT 格式来包装。OIDC协议授权返回⽰例:
{
\"resp_code\": 200, \"resp_msg\": \"ok\ \"datas\": {
\"access_token\": \"d1186597-aeb4-4214-b176-08ec09b1f1ed\ \"token_type\": \"bearer\
\"refresh_token\": \"37fd65d8-f017-4b5a-9975-22b3067fb30b\ \"expires_in\": 3599,
\"id_token\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vemx0MjAwMC5jbiIsImlhdCI6MTYyMTY5NjU4MjYxNSwiZXhwIjoxNjIxNjk2NjQyNjE1LCJzdWIiOiIxIiwibmFtZSI6IueuoeeQhuWRmCIsImxvZ2luX25hbWUiOiJhZG1pbiIsInBpY3R }}
可以看到与普通的 OAuth2 相⽐返回的信息中除了有 access_token 之外还多出了 id_token 属性。
三、什么是 ID Token
ID Token 是⼀个安全令牌,由授权服务器提供的包含⽤户信息的 JWT 格式的数据结构,得益于 JWT(JSON Web Token)的⾃包含性,紧凑性以及防篡改机制,使得 ID Token 可以安全的传递给第三⽅客户端程序并且容易被验证。id_token包含以下内容:
{
\"iss\": \"http://zlt2000.cn\ \"iat\": 1621696582615, \"exp\": 16216962615, \"sub\": \"1\
\"name\": \"管理员\
\"login_name\": \"admin\
\"picture\": \"http://xxx/头像.png\ \"aud\": \"app\
\"nonce\": \"t49bpg\"}
iss:令牌颁发者iat:令牌颁发时间戳exp:令牌过期时间戳sub:⽤户
idname:⽤户姓名
login_name:⽤户登录名picture:⽤户头像
aud:令牌接收者,OAuth应⽤
IDnonce:随机字符串,⽤来防⽌重放攻击
3.1. 与 JWT 的 Access Token 区别
是否可以直接使⽤ JWT ⽅式的 Access Token 并在 Payload 中加⼊⽤户信息来代替 ID Token 呢?
虽然在 Access Token 中可以加⼊⽤户的信息,并且是防篡改的,但是⽤户的每次请求都需要携带着 Access Token,这样不但增加了带宽,⽽且很容易泄露⽤户的信息。
3.2. 与 UserInfo 端点的区别
通常 OIDC 协议都需要另外提供了⼀个 Get /userinfo 的 Endpoint,需要通过 Access Token 调⽤该 Endpoint 来获取详细的⽤户信息,这个⽅法和 ID Token 同样都可以获取⽤户信息,那两者有什么区别呢?
相⽐较于 Get /userinfo 的接⼝使⽤ ID Token 可以减少远程 API 调⽤的额外开销;使⽤那个主要是看 需求,当你只需要获取⽤户的基本信息直接使⽤ ID Token 就可以了,并不需要每次都通过 AccessToken 去调⽤ Get /userinfo 获取详细的⽤户信息。
四、OIDC 单点登录流程
下⾯我们看⼀个 OIDC 协议常⽤的场景,就是具有 独⽴⽤户体系 系统间的单点登录,意思指的是⽤户数据并不是统⼀共⽤的,⽽是每个系统都拥有⾃⼰独⽴的⽤户数据,所以流程最后增加了⼀步 ⾃动注册⽤户。
⼤部分的流程与 OAuth2 的授权码模式相同这⾥就不多讲述了,其中下⾯两个步骤需要说明⼀下:
解析 ID Token 的公钥可以是预先提供给第三⽅系统也可以是提供接⼝获取。
⾃动注册⽤户 指的是第⼀次单点登录的时候,由于⽤户信息不存在需要在本系统中⽣成该⽤户数据;例如你从未在 CSDN 中注册也可以使⽤微信来登录该⽹站。
五、Spring Security 实现
先说⼀下扩展最终的⽬标是需要达到以下效果:
授权码模式:/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code
OIDC 模式:/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code id_token
⽬标是要通过在 response_type 中的传值来控制是否使⽤ OIDC 模式,如果使⽤则在 response_type 中增加 id_token 的值。
由于需要在 OAuth2 返回的内容中添加 ID Token 属性,所以实现这个扩展的关键就是需要通过 Security 的 TokenEnhancer 来为 Token 添加⾃定义字段;定义 TokenEnhancer 的 Bean 来扩展 Token:
通过授权的 response_type 参数来判断是否需要⽣成 id_token。⽣成 ID Token 的 JWT:
PS:上⾯只列出了部分关键代码,完整代码请通过下⾯的 demo 地址去下载。
六、完整的 demo 下载地址
到此这篇关于基于Security实现OIDC单点登录的⽰例代码的⽂章就介绍到这了,更多相关Security实现OIDC单点登录内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!