我们有一个基于spring boot的微服务架构,我们有多个微服务器相互通信,还有一个连接到不同微服务的Javascript UI .
由于这是一个内部应用程序,我们需要将它们连接到我们的SAML2 endpoints 以提供SSO,因此将所有这些连接起来让我感到头疼 . 理想情况下,微服务在它们之间使用oAuth2(JWT)和UI,但用户身份验证是通过SAML2完成的
以下我想用此实现:
-
UI客户端使用JWT与微服务进行通信
-
微服务也使用JWT相互通信 . 当用户向微服务发起请求并且微服务需要来自另一个微服务的更多数据时,它使用用户JWT令牌(这应该相当容易) .
-
拥有一个中央身份验证微服务,负责生成新令牌并根据SAML endpoints 对用户进行身份验证 .
-
在身份验证微服务中存储一些SAML详细信息(例如角色)
所以我尝试了很多不同的东西 . 我能说的是以下内容:
-
在微服务和JWT之间使用OAuth工作正常,并不是一个真正的问题(例如,这个链接是一个很好的教程来设置它http://www.swisspush.org/security/2016/10/17/oauth2-in-depth-introduction-for-enterprises)
-
使用带有spring-security-saml-dsl的SAML也很简单,效果很好
-
我已经结合了spring-security-saml-dsl实现了JWT,并且也很好用(类似于:https://www.sylvainlemoine.com/2016/06/06/spring-saml2.0-websso-and-jwt-for-mobile-api/除了我使用spring-security-saml-dsl)我不喜欢它,因为它使用了很多自定义代码与所有过滤器等,但将是一种方式去 .
我想我在哪里努力的是oauth2资源服务器和SAML服务的连接点 .
关于SAML我有以下工作正常:
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${security.saml2.metadata-url}")
String metadataUrl;
@Value("${server.ssl.key-alias}")
String keyAlias;
@Value("${server.ssl.key-store-password}")
String password;
@Value("${server.port}")
String port;
@Value("${server.ssl.key-store}")
String keyStoreFilePath;
@Autowired
SAMLUserDetailsService samlUserDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/oauth/**").authenticated()
.and().exceptionHandling()
.and()
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml()).userDetailsService(samlUserDetailsService)
.serviceProvider()
.keyStore()
.storeFilePath("saml/keystore.jks")
.password(this.password)
.keyname(this.keyAlias)
.keyPassword(this.password)
.and()
.protocol("https")
.hostname(String.format("%s:%s", "localhost", this.port))
.basePath("/")
.and()
.identityProvider()
.metadataFilePath(this.metadataUrl);
}
}
这很好 . 因此当我点击受保护的 endpoints 时,我将被重定向并可以通过saml登录 . 然后我在samlUserDetailsService中获得userdetails .
关于oauth我有这样的事情:
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore())
.tokenEnhancer(accessTokenConverter())
.authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("ABC"); //needs to be changed using certificates
return converter;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")
.secret("acmesecret")
.authorizedGrantTypes("refresh_token", "authorization_code")
.autoApprove(true)
.scopes("webapp")
.accessTokenValiditySeconds(60)
.refreshTokenValiditySeconds(3600);
}
}
这部分也适用于我有@EnableResourceServer的其他微服务器
据我所知,OAuth部分,ClientDetailsServiceConfigurer只配置客户端应用程序(在我的情况下是其他微服务),我应该使用client_credentials类型的授权(但不确定) . 但是我如何在SAML部分接线并不清楚......
作为替代方案,我正在考虑拆分它 . 创建一个OAuth授权服务的微服务和另一个执行SAML位的微服务 . 在这种情况下,如果用户通过身份验证,SAML微服务将连接到SAML并提供类似/ me的 endpoints . 然后,OAuth授权服务将使用SAML微服务检查用户是否在那里进行了身份验证,如果是这种情况,则提供令牌 . 关于刷新令牌,我也会这样做 . 据我所知,我会在public void configure(ClientDetailsServiceConfigurer clients)抛出Exception {}方法中实现这种逻辑 .
如果有更好的方法,请告诉我!