基于Spring Authorization Server实现SAML 2.0联邦SSO登录的方案咨询
核心结论
Spring Authorization Server(SAS)官方目前不原生支持SAML 2.0协议,它的核心定位是实现OAuth 2.1和OpenID Connect 1.0标准。但可以通过将SAS作为SAML Service Provider(SP)对接外部SAML Identity Provider(IDP),再把SAML断言转换为OAuth2身份信息的方式,实现你需要的流程。
实现流程与指南
目标流程:SAS登录页→重定向至SAML IDP登录页→用户登录→IDP返回SAML断言→SAS验证断言并生成JWT令牌
1. 引入依赖
需要同时引入Spring Authorization Server和Spring SAML 2.0 SP的核心依赖:
<!-- Spring Authorization Server --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-authorization-server</artifactId> <version>1.2.3</version> </dependency> <!-- Spring SAML 2.0 Service Provider --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-saml2-service-provider</artifactId> <version>6.2.3</version> </dependency>
2. 配置SAML 2.0 SP(SAS作为SP)
在application.yml中配置SAML IDP的元数据信息,包括实体ID、SSO地址、验证证书等:
spring: security: saml2: relyingparty: registration: saml-idp: entity-id: "https://your-sas-domain/saml/sp" assertion-consumer-service-url: "https://your-sas-domain/login/saml2/sso/saml-idp" idp: entity-id: "https://saml-idp-domain/idp/entity" single-sign-on-url: "https://saml-idp-domain/idp/sso" verification: credentials: - certificate-location: "classpath:saml-idp-cert.crt"
3. 整合SAML登录与Authorization Server
自定义SecurityFilterChain,将SAML登录流程接入SAS的身份验证体系:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize .anyRequest().authenticated() ) .saml2Login(saml2 -> saml2 .loginPage("/login") // 触发重定向到SAML IDP的入口页 .successHandler((request, response, authentication) -> { // SAML登录成功后,将SAML认证信息存入SecurityContext SecurityContextHolder.getContext().setAuthentication(authentication); }) ); return http.build(); } // 配置Authorization Server客户端信息 @Bean public RegisteredClientRepository registeredClientRepository() { RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString()) .clientId("your-sp-client-id") .clientSecret("{noop}your-sp-client-secret") .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) .redirectUri("https://your-client-domain/callback") .scope(OidcScopes.OPENID) .scope(OidcScopes.PROFILE) .build(); return new InMemoryRegisteredClientRepository(client); } // 配置Authorization Server基础设置 @Bean public AuthorizationServerSettings authorizationServerSettings() { return AuthorizationServerSettings.builder() .issuer("https://your-sas-domain") .build(); } }
4. 转换SAML断言为OAuth2用户信息
自定义UserDetailsService,将SAML断言中的用户信息转换为Authorization Server可识别的UserDetails:
@Service public class SamlUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String nameId) throws UsernameNotFoundException { // 从SAML断言中提取用户标识(NameID)和权限信息 return User.withUsername(nameId) .password("{noop}") // SAML登录无需本地密码 .authorities("ROLE_USER") .build(); } }
5. 测试流程
- 客户端发起OAuth2授权请求:
https://your-sas-domain/oauth2/authorize?client_id=your-sp-client-id&response_type=code&redirect_uri=https://your-client-domain/callback&scope=openid - 页面跳转到SAS登录页,自动重定向至SAML IDP登录界面
- 用户在IDP完成登录后,IDP将SAML断言发送至SAS的ACS地址
- SAS验证断言有效性,生成用户Authentication
- 用户完成授权确认后,SAS返回授权码至客户端
- 客户端使用授权码交换JWT令牌:
POST https://your-sas-domain/oauth2/token
关键注意事项
- 确保SAML IDP与SAS的实体ID、ACS地址完全匹配,证书验证配置正确
- 可通过自定义
OidcUserInfoMapper将SAML断言中的额外字段(如邮箱、角色)写入JWT声明 - 生产环境建议使用数据库存储RegisteredClient和用户信息,而非内存实现
内容的提问来源于stack exchange,提问作者pradhan
相关产品推荐
相关产品推荐

