Spring Boot 4.0 OAuth2 与 SSO 单点登录实战
前言
企业内部通常已经有统一身份提供商。订单平台再维护一套员工密码,会带来离职账号残留、重复改密和多套登录体验。
本章接入标准 OIDC 授权码流程。用户在企业登录页完成认证,平台用授权码换取 ID Token,再把企业用户组映射为应用角色。
企业凭据必须由环境变量注入。本文不包含任何真实 Client Secret,完整代码位于 dvsusan/spring-boot4-demo。
最终结果
访问受保护的 /sso/me 时,应用跳转到企业身份提供商;登录成功后回到平台,并显示邮箱、姓名和应用权限。

图 1:SSO 的关键不是“跳转页面”,而是校验 ID Token 后完成企业身份到应用权限的映射。
第 1 步:准备 OIDC 客户端
在企业身份平台注册 Web 应用,登记回调地址:
http://localhost:18106/login/oauth2/code/corp-oidc生产环境改成真实 HTTPS 域名。应用至少需要 openid、profile、email 三个 Scope,并拿到 Client ID、Client Secret 和 Issuer。
第 2 步:配置授权码流程
把凭据放到环境变量,不写进 Git:
spring:
security:
oauth2:
client:
registration:
corp-oidc:
# 这些值由企业身份平台分配,示例只展示变量名。
client-id: ${OIDC_CLIENT_ID}
client-secret: ${OIDC_CLIENT_SECRET}
provider: corp-oidc
scope: openid,profile,email
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
provider:
corp-oidc:
# 标准 OIDC 使用 discovery,也可显式配置各端点。
issuer-uri: ${OIDC_ISSUER}
demo:
chapter6:
enabled: true
oauth2:
enabled: trueregistrationId 是 corp-oidc,回调路径必须与身份平台登记值完全一致。HTTP 与 HTTPS、端口和尾斜杠不同都会导致重定向错误。
第 3 步:建立独立 SSO 安全链
SSO 使用浏览器会话保存授权请求和登录状态,因此与 JWT API 的完全无状态链分开:
http.securityMatcher(
"/sso/**",
"/oauth2/**",
"/login/oauth2/**"
)
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo
.userAuthoritiesMapper(authoritiesMapper)
)
.defaultSuccessUrl("/sso/me", true)
)
.logout(logout -> logout
.logoutUrl("/sso/logout")
.logoutSuccessUrl("/")
);securityMatcher 必须包含 /oauth2/** 和 /login/oauth2/**,否则 Spring Security 生成的登录入口和回调路径会落到普通 MVC 资源处理器。
第 4 步:映射企业用户组
SsoIdentityMapper 不依赖 Servlet,便于单元测试:
public SsoIdentity map(boolean emailVerified, List<String> groups) {
if (!emailVerified) {
return new SsoIdentity(List.of(), List.of());
}
if (groups.contains("platform-admins")) {
return new SsoIdentity(
List.of("ADMIN"),
List.of(
"order:read",
"order:write",
"order:delete",
"payment:write",
"data:all",
"data:pii:read",
"data:cost:read"
)
);
}
if (groups.contains("sales-analysts")) {
return new SsoIdentity(
List.of("ANALYST"),
List.of(
"order:read",
"data:department",
"data:pii:read"
)
);
}
return new SsoIdentity(List.of("EMPLOYEE"), List.of("order:read"));
}不能直接信任客户端传来的组名。组信息必须来自已验签的 ID Token 或服务端调用身份平台得到的用户信息。
第 5 步:转换 Spring Security 权限
SsoAuthoritiesMapper 从 OidcUserAuthority 读取已验证声明:
boolean emailVerified = Boolean.TRUE.equals(
oidcAuthority.getIdToken().getClaimAsBoolean("email_verified")
);
List<String> groups = oidcAuthority.getIdToken()
.getClaimAsStringList("groups");
SsoIdentityMapper.SsoIdentity identity = identityMapper.map(
emailVerified,
groups == null ? List.of() : groups
);邮箱未验证时返回空权限,避免只用邮箱地址就完成账号接管。真实企业还会校验 hd、租户 ID、员工状态和组前缀。
第 6 步:启动并观察跳转
OIDC_CLIENT_ID='<client-id>' \
OIDC_CLIENT_SECRET='<client-secret>' \
OIDC_ISSUER='https://idp.example.com' \
java -jar demo-web/target/demo-web-1.0.0-SNAPSHOT.jar \
--spring.profiles.active=chapter6 \
--server.port=18106浏览器访问:
http://localhost:18106/sso/me预期先返回 302 到 /oauth2/authorization/corp-oidc,再跳转到企业登录页。登录成功后回到 /sso/me。
如果没有企业身份平台,可以运行项目中的占位配置测试:
mvn -pl demo-web -am \
-Dtest=Chapter6OidcConfigurationTest \
-Dsurefire.failIfNoSpecifiedTests=false \
test该测试不访问外网,只验证 /sso/me 和 /oauth2/authorization/corp-oidc 的两次 302 跳转,以及用户组映射结果。真实登录仍需要企业凭据。
OIDC 与普通 OAuth2 的区别
OAuth2 是授权框架,OIDC 在 OAuth2 之上增加身份层。access_token 用来访问资源,id_token 用来证明“当前用户是谁”。
应用不应该拿第三方 access_token 直接当自己的业务 JWT。正确做法是校验 ID Token、完成组映射,再建立自己的会话或签发自己的业务令牌。
常见问题排查
| 现象 | 原因 | 处理方式 |
|---|---|---|
| 跳转后提示 redirect_uri_mismatch | 回调地址未登记或协议端口不同 | 对比身份平台与应用配置 |
| 登录后权限为空 | 企业组名与映射表不一致 | 打印经脱敏的组名并修正映射 |
/oauth2/authorization/... 返回 500 | 安全链没有匹配内部授权端点 | 加入 /oauth2/** 和 /login/oauth2/** |
| 提示 issuer 无法发现 | 应用无法访问 discovery 地址 | 检查网络、证书和代理 |
| 邮箱未验证却没有拒绝 | 映射逻辑忽略了声明 | 以 email_verified=true 为前置条件 |
练习题
增加 auditor 企业组,只授予 order:read;再限制 platform-admins 必须同时属于 tenant_acme。验收标准是无租户声明的管理员组不会自动获得跨租户权限。
总结
SSO 的价值是统一企业身份,不是取消应用授权。标准 OIDC 负责证明用户身份,应用仍需完成组映射、租户绑定、最小权限和审计。
下一篇把用户、角色、权限和租户串成完整的 RBAC 决策模型。
上一节:JWT 登录与刷新
下一节:多租户 RBAC
相关阅读:多租户数据库设计
返回课程目录
13 个企业级实战项目 · 源码 + 教程 + 答疑
简历包装指导AI Agent 实战高并发·微服务Offer 导向持续更新3000+ 同行交流1V1 答疑3 天包退
覆盖高并发、微服务、分布式与 AI Agent:100万QPS短链、企业智能知识库、商城微服务、SaaS点餐、秒杀、刷题小程序、代码生成器、AI Agent 等。券后 ¥129(原价 ¥159),不满意 3 天包退。
