先上结论: 这个过程,有三个角色:
- 用户
- 客户端应用
- 身份提供者
这个例子中, 实现oidc单点登录的客户端应用是Pageplug; 身份提供者是keycloak平台;
简言之就是:用户想使用身份提供者给的身份,进入实现了单点登录的客户端应用。
过程
使用 keycloak平台
1.拉取并运行keycloak提供的镜像
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:22.0.3 start-dev
注意端口号别和后端冲突,
启动容器之后就可以访问 keycloak控制台 了
2.创建realm
填写name,创建
3.创建user
填写用户名,创建
账号:user3
密码: 123456
这里的邮箱,对应的是你在Pageplug邮箱账号,比如,你使用这个账号密码第三方登录验证通过后,登录Pageplug的邮箱账号是123@qq.com
创建之后可以在Credentials设置密码;Temporary设置关闭
4.创建client
client id:client3
client secret: 123456
返回 管理员后台,切换刚刚创建的realm(默认新建时就会切换了)
创建client,填写client id,client type选择OpenID Connect
Standard flow设置打开
设置回调url和域名,回调url复制Pageplug中提供的
5.在Pageplug中填写配置
点击 realm settings,打开 OpenID Endpoint Configuration
根据对应信息对号入座
信息清单
Client ID:client3
Client Secret:123456
Authorization URL:http://localhost:8081/realms/pageplug3/protocol/openid-connect/auth
Token URL:http://localhost:8081/realms/pageplug3/protocol/openid-connect/token
User Info URL:http://localhost:8081/realms/pageplug3/protocol/openid-connect/userinfo
JWK Set URL:http://localhost:8081/realms/pageplug3/protocol/openid-connect/certs
Logout URL:http://localhost:8081/realms/pageplug3/protocol/openid-connect/logout
Scope:openid
Username Attribute:email
6.测试oidc单点登录
保存重启,右上角头像退出登录
在登录页点击oidc登录
填写第3步创建的user账号密码
登录成功会重定向到首页
原理解析
1.进入oidc单点登录
会跳转至
这是Pageplug写的一个接口
根据该接口返回的响应字段location可知:会重定向到
http://localhost:8081/realms/pageplug3/protocol/openid-connect/auth
也就是配置信息中的 Authorization URL,并且,带上了以下参数:
- response_type
- client_id
- scope
- state
- redirect_uri
- nonce
查看下一个请求也可以看出
这些参数有什么作用呢?
response_type:表示客户端应用向身份提供者认证用户的身份时,期望的响应类型,响应类型有code、token、id token;
client_id: 用户在身份提供者那里可以有很多客户端应用(Pageplug只是其中之一),用来标识应用;
scope: 指定请求的范围或权限,范围是openid表示请求是OIDC请求,还有profile、email等用于请求用户个人信息;
state: 客户端应用(Pageplug)生成的随机字符串,在响应中可以验证其一致性,确保请求的完整性,防止token被篡改;
redirect_uri:身份提供者(keycloak)认证完之后,返回的地址;
nonce: 客户端应用(Pageplug)生成的随机值,类似state,收到id token时验证其一致性,防止id token被篡改;
2.填入user的账号密码,登录
这时会跳转至 http://localhost:8081/realms/pageplug3/login-actions/authenticate, 这是身份提供者(keycloak)提供的一个接口,验证用户的身份
会带上以下参数:
- session_code
- execution
- client_id
- tab_id
- username
- password
根据该接口返回的响应字段location可知:会重定向到
也就是配置信息中的Redirect URL, 并且带上以下参数:
- state
- session_state
- code
从下一个请求可以看出:
这三个参数是上一个请求(http://localhost:8081/realms/pageplug3/login-actions/authenticate)响应返回的,state没变,表示请求没被更改;
code是用户经过身份提供者(keycloak)认证成功之后返回的,用于后续客户端应用(Pageplug)从身份提供者那里获取用户的token,进而获取用户的其他信息;
而session_state就很关键了:它是由身份提供者(keycloak)生成和维护的,每当用户通过身份提供者登录认证或者与身份提供者进行其他交互的时,身份提供者将生成一个新的session_state值。客户端应用(Pageplug)可以在每个认证请求中将session_state传递给身份提供者,并在响应中检查它,这样使得客户端应用可以了解用户的会话状态是否处于活动状态;
同时,通过比较不同认证请求中的session_state值,客户端应用可以检测用户是否已经通过单点登录进行了认证。如果session_state值在不同认证请求之间保持不变,那么用户可能已经登录并且会话处于活动状态。这允许客户端应用为已认证的用户提供访问权限,而无需用户重新登录;
还有,session_state还可以防止会话劫持。通过将session_state与token一起传递给客户端应用程序,并在每个认证请求中验证它,客户端应用可以确保用户的会话没有被劫持或篡改。
最后,用户身份认证成功,会重定向到 /application
那先前配置的Token URL、UserInfo URL、JWK Set URL、Logout URL有何作用呢?
当客户端应用(Pageplug)获取到上述的code时,可以去Token URL向身份提供者(keycloak)请求用户的Token,而拿到用户的Token之后,就可以去UserInfo URL请求用户的更多信息;
而JWK Set URL是客户端应用(Pageplug)向身份提供者(keycloak)发起解析和检查Token是否正确、是否被篡改请求的;
而Logout URL是客户端应用告知身份提供者将用户的会话状态取消活动的;