为OAuth2 Spring Boot创建自定义OpenID身份提供商
Hey Alex, 我来帮你理清在Spring Boot OAuth2基础上搭建自定义OpenID身份提供商(IDP)的具体路径——其实OIDC本身就是OAuth2的上层扩展,所以咱们不用从零开始,只需要给现有OAuth2授权服务补上OIDC的核心特性就行~
核心逻辑先搞懂
OIDC本质是在OAuth2的授权码流程上,新增了身份认证的标准化能力:它通过id_token(一种JWT格式的令牌)来传递用户的身份信息,同时提供了一系列标准端点(比如用户信息端点、JWKS密钥端点)让客户端能安全地验证用户身份。你之前做的OAuth2授权是管“能不能访问API”,现在OIDC要管“你是谁”,两者完全兼容。
现在Spring官方推荐用spring-security-oauth2-authorization-server这个模块(旧的Spring Security OAuth已经停止维护了,建议升级到这个),下面是具体操作:
1. 补上OIDC相关依赖
如果还没加,在你的pom.xml(Maven)里添上:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-authorization-server</artifactId> <version>1.2.3</version> <!-- 用最新稳定版就行 --> </dependency>
Gradle的话就加这个:
implementation 'org.springframework.security:spring-security-oauth2-authorization-server:1.2.3'
2. 给现有授权服务器配置OIDC特性
Spring的这个模块默认已经集成了OIDC的核心组件,你只需要在配置里启用它:
如果你用的是新版Spring Security 6+的配置方式(推荐)
@Bean public RegisteredClientRepository registeredClientRepository() { RegisteredClient yourClient = RegisteredClient.withId(UUID.randomUUID().toString()) .clientId("你的客户端ID") .clientSecret("{bcrypt}你的客户端密钥") // 记得用BCrypt加密 .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) .redirectUri("https://你的客户端回调地址") // 必须添加OIDC的标准scope,openid是核心,profile/email可选 .scope(OidcScopes.OPENID) .scope(OidcScopes.PROFILE) .scope(OidcScopes.EMAIL) .scope("你原来的OAuth2权限范围") .build(); return new InMemoryRegisteredClientRepository(yourClient); } // 默认配置就会启用所有OIDC标准端点,不用额外改 @Bean public AuthorizationServerSettings authorizationServerSettings() { return AuthorizationServerSettings.builder().build(); }
如果你用的是旧版的@EnableAuthorizationServer配置
@Configuration @EnableAuthorizationServer public class AuthServerConfig implements AuthorizationServerConfigurer { @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("你的客户端ID") .secret("{bcrypt}你的客户端密钥") .authorizedGrantTypes("authorization_code", "refresh_token") // 一定要加openid这个scope,不然不会生成id_token .scopes("openid", "profile", "email", "你原来的权限范围"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .authenticationManager(authenticationManager) .userDetailsService(userDetailsService) // 启用OIDC的ID Token生成器 .oidcIdTokenGenerator(customOidcIdTokenGenerator()); } // 自定义ID Token里的用户信息(比如加用户ID、昵称这些自定义字段) @Bean public OidcIdTokenGenerator customOidcIdTokenGenerator() { DefaultOidcIdTokenGenerator generator = new DefaultOidcIdTokenGenerator(); generator.setClaimMapper(claims -> { // 从Authentication里拿你的用户对象,把信息塞到ID Token里 YourUserEntity user = (YourUserEntity) claims.get(Principal.class.getName()); claims.put("user_id", user.getId()); claims.put("nickname", user.getNickname()); return claims; }); return generator; } // 你原来的tokenServices、authenticationManager这些配置保持不变就行 }
3. 不用自己写OIDC标准端点!
Spring的授权服务器已经帮你实现了所有OIDC要求的标准端点,直接就能用:
- 授权端点:
/oauth2/authorize(请求时要带scope=openid才会走OIDC流程) - Token端点:
/oauth2/token(返回的响应里会包含id_token、access_token、refresh_token) - 用户信息端点:
/userinfo(用access_token就能获取用户详细信息) - JWKS密钥端点:
/.well-known/jwks.json(客户端用来验证ID Token签名的公钥) - OIDC发现端点:
/.well-known/openid-configuration(客户端可以自动获取IDP的所有配置信息)
4. 自定义身份信息映射(如果需要)
如果你的用户系统不是用默认的UserDetails,可以实现OidcUserInfoMapper接口,把你的用户对象转换成OIDC标准的OidcUserInfo,这样用户信息端点就能正确返回符合标准的用户数据。
5. 测试一下流程
用Postman或者随便一个OIDC客户端工具测一遍:
- 访问授权端点:
GET /oauth2/authorize?response_type=code&client_id=你的客户端ID&redirect_uri=你的回调地址&scope=openid%20profile - 登录你的系统,授权后会跳转到回调地址,拿到授权码
code - 用授权码换Token:
POST /oauth2/token,参数填grant_type=authorization_code、code=刚才拿到的码、redirect_uri=你的回调地址、client_id和client_secret - 看响应里的
id_token,解码后应该能看到用户的身份信息(比如sub是用户唯一标识,还有你自定义的字段) - 调用
/userinfo端点,带上access_token,应该能拿到用户的详细信息
几个关键注意点
- 一定要给客户端配置
openid这个scope,否则不会生成id_token,等于没启用OIDC - ID Token要用非对称加密(RSA)签名,Spring默认会自动生成密钥对,但生产环境建议用自己的密钥(可以配置在
application.yml里) - ID Token里的
sub字段是用户的唯一标识,必须要有,其他字段比如name、email是可选的,尽量符合OIDC标准 - 如果要做单点登录(SSO),多个客户端只要信任这个IDP,就能用
id_token实现跨应用登录
内容的提问来源于stack exchange,提问作者Alex Man
相关产品推荐
相关产品推荐

