本帖最后由 小懒 于 2026-3-19 09:57 编辑
说明: 1、本文基于个人搭建的测试环境实践整理,不涉及任何客户信息。 2、本文内容为实际对接过程中的经验总结,仅供参考。 3、文末附完整PDF版本,包含详细配置过程及示例,可自行下载参考。
目录:一、场景说明 二、对接前提(必须:接口文档 + 参数) 四、OAuth侧配置(Keycloak,客户配合) 八、总结(实施经验)
一、场景说明 1.1 对接本质 在实际项目中,对接 OAuth2 并不是"自己设计认证流程",而是: 1、客户已有统一身份系统(如 Keycloak),零信任进行对接接入
2、零信任不维护用户,直接对接客户现有账号体系1.2 对接目标 1、实现统一认证(SSO)
2、用户使用企业现有账号登录零信任
3、零信任仅做访问控制,身份认证由OAuth服务器负责
1.3 适用场景 1、企业已有统一身份管理平台(如Keycloak、Azure AD)
2、需要实现单点登录(SSO)
二、对接前提(必须:接口文档 + 参数) 实际工程第一步,不是配置,而是拿参数。 2.1 获取接口文档(关键) 客户需提供或自行获取OAuth服务器的元数据接口: http://{host}:{port}/realms/{realm}/.well-known/openid-configuration 以Keycloak为例验证接口: 浏览器访问http://10.253.253.66:8080/realms/demo/.well-known/openid-configuration 返回示例:
2.2 核心接口地址(必须明确) 以 Keycloak 为例: 接口用途 | 端点地址 | 说明 | 认证地址(Authorization) | http://10.253.253.66:8080/realms/demo/protocol/openid-connect/auth | 获取授权码 | Token地址 | http://10.253.253.66:8080/realms/demo/protocol/openid-connect/token | 用code换取token
| 用户信息地址 | http://10.253.253.66:8080/realms/demo/protocol/openid-connect/userinfo | 获取用户信息 | 注销地址 | http://10.253.253.66:8080/realms/demo/protocol/openid-connect/logout | 清理会话 |
2.3 客户须提供参数 参数 | 说明 | 示例 | client_id | 客户端ID | atrust | client_secret | 客户端密钥 | FSIF6POw2R7p3I0Rjsc9kH1MRnxvVFRp | redirect_uri | 回调地址 | https://xxx/passport/passport/v1/auth/httpsOauth2
(固定格式:零信任接入地址+后缀) | scope | 请求的权限范围 | openid |
三、OAuth2简要原理 3.1 四阶段流程(零信任实现) 阶段 | 说明 | 输出结果 | Authorization | 引导用户登录,获取授权码 | code(一次性,有效期短) | Token | 使用code换取access_token | access_token(访问令牌) | UserInfo | 使用token获取用户信息 | 用户数据(username、email等) | Logout(可选) | 清除会话,实现单点注销 | 注销成功 |
说明: 1、标准OAuth2协议通常为2步:Authorization + Token
四、OAuth侧配置(Keycloak,客户配合) 4.1 创建 Client 配置路径: Realm → Clients → Create 核心配置项: 配置项 | 配置值 | 说明 | Client ID | | 客户端标识,需与零信任配置一致 | Client Protocol | | 固定值 | Client authentication | | 必须使用(需要client_secret) | Standard Flow Enabled | | 必须开启(即Authorization Code流程) |
4.2 获取client_secret 配置路径: Clients → atrust → Credentials 操作步骤: 1、切换到Credentials标签页
2、点击Regenerate生成新的Client Secret
3、复制保存
4.3 配置 RedirectURI(最关键) 配置路径: Clients → atrust → Settings → Valid Redirect URIs / Valid post logout redirect URIs 配置值: https://xxxxxx.top:4430/passport/v1/auth/httpsOauth2 要求: 1、必须完全一致(协议/域名/端口/路径)
2、不能有任何差异,否则直接报错
3、 支持通配符:https://xxxxxx.top:4430/*
五、零信任配置(核心) 5.1 阶段1:Authorization(获取code) 功能: 引导用户跳转至Keycloak登录页,获取授权码 接口: http://10.253.253.66:8080/realms/demo/protocol/openid-connect/auth 请求方法: GET URL参数: 参数 | 配置值 | 说明 | response_type | | 固定值,指定授权码模式 | client_id | | Keycloak中创建的Client ID | redirect_uri | https://xxxxxx.top:4430/passport/v1/auth/httpsOauth2 | 回调地址(必须与OAuth侧一致) 固定格式:零信任接入地址+后缀 | scope | | 请求的用户信息范围 | state | | 防CSRF攻击(可选) |
响应解析: 1、从回调URL中提取code参数
5.2 阶段2:Token(获取token) 功能: 使用授权码换取access_token 接口: http://10.253.253.66:8080/realms/demo/protocol/openid-connect/token 请求方法: POST 请求头参数: Content-Type:application/x-www-form-urlencoded 请求体参数: | 参数 | | | | | | | | | | | | | FSIF6POw2R7p3I0Rjsc9kH1MRnxvVFRp | | | https://xxxxxx.top:4430/passport/v1/auth/httpsOauth2 | |
【关键】必须配置预处理脚本(响应数据预处理) function AfterResponse(response, result) { // TODO: 在此添加nodejs代码 env.access_token =JSON.parse(response.body).access_token; result.access_token = env.access_token; } AfterResponse(response, result); 说明: 1、Token阶段必须写脚本
2、access_token必须写入env环境变量
3、UserInfo阶段依赖该变量,否则全部失败 认证成功条件: 5.3 阶段3:UserInfo(获取用户) 功能: 使用access_token获取用户信息 接口: http://10.253.253.66:8080/realms/demo/protocol/openid-connect/userinfo 请求方法: GET URL参数: | 参数 | | | | Bearer {{env.access_token}} | |
响应提取: 1、提取preferred_username字段,映射为本地【用户名】变量 认证成功条件: 5.4 阶段4:Logout(可选) 功能: 清除Keycloak会话,实现单点注销 接口: http://10.253.253.66:8080/realms/demo/protocol/openid-connect/logout 请求方法: GET URL参数: 说明: 1、用于清理Keycloak会话
2、不配置也能登录
3、但可能出现:退出后自动登录(因为Keycloak会话未清除)
六、验证测试 6.1 业务验证 验证步骤: 访问客户端:
1、使用浏览器访问客户端接入地址
2、应自动跳转至Keycloak登录页
3、输入Keycloak账号信息
4、成功后应跳转回客户端应用
5、确认用户可以正常访问授权的资源
6、点击注销登录
7、重定向到oauth,注销确认,oauth也联动注销成功
8、日志查看
七、常见问题 7.1 redirect_uri不一致 现象: 1、Keycloak返回错误:Invalid redirect_uri
原因: 1、零信任侧与OAuth侧的redirect_uri不一致(协议/端口/路径)
https://xxxxxx.top:4430/xxx,但Keycloak配置http://xxxxxx.top:4430/xxx(协议不同)解决方法: 1、严格对比两边的redirect_uri,确保完全一致
2、包括协议(http/https)、域名、端口号、路径
7.2 Token 获取失败(invalid_grant) 现象: 1、Token阶段返回:{"error":"invalid_grant","error_description":"Invalid code or redirect_uri"}
原因: 1、code已使用(OAuth2标准要求code只能使用一次)
2、code已过期(code有效期可能配置的比较短,如30秒)
3、
解决方法: 1、确保code仅使用一次
2、在code有效期内完成兑换
7.3 获取不到用户(UserInfo失败) 现象:
原因: 1、scope未配置openid 2、access_token未正确传递 解决方法: 1、确保scope包含openid
2、确认Token阶段预处理脚本正确执行
7.4 登录循环 现象: 1、用户登录后,刷新页面又要求重新登录
原因: 1、token未保存到环境变量
2、UserInfo阶段未成功提取用户信息
解决方法: 1、检查Token阶段预处理脚本
2、确认UserInfo阶段成功提取username3、
7.5 退出无效 现象:
原因: 1、未配置Logout阶段
解决方法: 1、配置Logout阶段
7.6 变量引用语法错误 现象: 1、URL中出现%7B%7Benv.code%7D%7D(URL编码后的双大括号)
原因: 1、使用了单大括号${env.code}而非双大括号
解决方法: 1、必须使用双大括号:{{env.code}}、{{env.access_token}}
八、总结(实施经验) 8.1 对接要点总结 要点 | 说明 | 对接第一步一定是拿接口文档 | 不要急着配置,先获取OAuth服务器的端点信息 | OAuth侧必须先配置Client | Client ID、Client Secret、Redirect URI是三大核心参数 | Token阶段脚本是关键点 | 预处理脚本必须编写,access_token必须写入env | redirect_uri是最大坑 | 必须完全一致,包括协议/域名/端口/路径 | logout可选,但建议配置 | 否则退出后可能出现自动登录问题 |
8.3 可扩展对接的OAuth2服务器 本方案不仅适用于Keycloak,其他标准OAuth2服务也可作为参考: OAuth2服务器 | 说明 | Keycloak | 开源身份与访问管理平台 | Azure AD | 微软企业级身份服务 | Okta | 企业身份与访问管理平台 | GitHub | 开发者社区OAuth2认证 | GitLab | 代码托管平台OAuth2认证 | 钉钉/企业微信 | 国内主流企业IM的OAuth2接口 |
|