在实现基于Spring Security Oauth2库构建的OpenID连接时遇到问题。 (阅读有关problem in a separate question的更多信息。)在研究它时,我读了documentation for the @EnableOauth2Client
annotation,其中说:
在使用Spring Security并希望使用来自一个或多个OAuth2授权服务器的授权代码授予的Web应用程序中为OAuth2客户端启用配置。要利用此功能,您需要在DelegatingFilterProxy的应用程序中使用全局servlet过滤器,该过滤器委派给名为“ oauth2ClientContextFilter”的bean。过滤器到位后,您的客户端应用即可使用此批注提供的另一个bean(一个AccessTokenRequest)来创建OAuth2RestTemplate,例如
@Configuration @EnableOAuth2Client public class RemoteResourceConfiguration { @Bean public OAuth2RestOperations restTemplate(OAuth2ClientContext oauth2ClientContext) { return new OAuth2RestTemplate(remote(), oauth2ClientContext); } }
使用客户端凭据授予的客户端应用程序不需要AccessTokenRequest或作用域的RestOperations(状态对于应用程序是全局的),但是它们仍应使用过滤器来触发OAuth2RestOperations,以在必要时获取令牌。使用 [sic] 密码授予的应用需要在使用RestOperations之前在OAuth2ProtectedResourceDetails中设置身份验证属性,这意味着资源详细信息本身也必须针对每个会话(假设在系统)。
关于版本和文档的注意事项:本文档是2.0.4版本,即使我的项目正在使用较新的2.3.5链接,也可以从Spring Security project page链接到该文档。我们的其他Spring版本:Spring Boot 1.3.0,Spring Security 3.2.5,Spring Framework 4.2.3。
我不太明白这是什么意思,
您的DelegatingFilterProxy应用程序中的全局servlet过滤器,该过滤器委派给名为“ oauth2ClientContextFilter”的bean
这是我们配置休息模板的方式。
@Configuration
@EnableOAuth2Client
public class OpenIdConnectConfig {
@Bean
public OAuth2ProtectedResourceDetails openIdResourceDetails() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setClientId(clientId);
details.setClientSecret(clientSecret);
details.setAccessTokenUri(accessTokenUri);
details.setUserAuthorizationUri(userAuthorizationUri);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
details.setScope(oidcScopes);
details.setPreEstablishedRedirectUri(redirectUri);
details.setUseCurrentUri(false);
return details;
}
@Bean(name = "my.company.ui.security.OpenIdRestTemplate")
// ToDo: fix org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread
public OAuth2RestTemplate OpenIdRestTemplate(OAuth2ClientContext clientContext) {
return new OAuth2RestTemplate(openIdResourceDetails(), clientContext);
}
@Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
@Value("${oidc.clientId}")
private String clientId;
@Value("${oidc.clientSecret}")
private String clientSecret;
@Value("${oidc.accessTokenUrl}")
private String accessTokenUri;
@Value("${oidc.userAuthorizationUri}")
private String userAuthorizationUri;
@Value("${oidc.redirectUri}")
private String redirectUri;
@Value("#{'${oidc.scopes}'.split(',')}")
private List<String> oidcScopes;
}
执行身份验证的过滤器(删除了一些异常处理和用户处理代码):
public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter {
public OpenIdConnectFilter(
RequestMatcher requiresAuthenticationRequestMatcher,
AuthenticationService authenticationService
) {
super(requiresAuthenticationRequestMatcher);
setAuthenticationManager(new NoopAuthenticationManager());
}
@SuppressWarnings("RedundantThrows") // Matching overridden method
@Override
public Authentication attemptAuthentication(
HttpServletRequest request,
HttpServletResponse response
) throws AuthenticationException, IOException, ServletException {
// Required parameters (one-time access code, state) are retrieved from the context
OAuth2AccessToken oAuth2AccessToken = restTemplate.getAccessToken();
// Process the token, get the user details, return an Authentication object.
}
public void setRestTemplate(OAuth2RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
private static class NoopAuthenticationManager implements AuthenticationManager {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
}
}
private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdConnectFilter.class);
@Value("${oidc.clientId}")
private String clientId;
@Value("${oidc.issuer}")
private String issuer;
@Value("${oidc.jwt.jwk.url}")
private String jwkUrl;
private final AuthenticationService authenticationService;
private OAuth2RestTemplate restTemplate;
}
以及用于设置Spring Security FilterProxyChain的安全配置:
@Configuration
@EnableWebSecurity
@EnableOAuth2Client
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
@SuppressWarnings("unchecked")
protected void configure(HttpSecurity http)
throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.csrf()
.disable()
.authorizeRequests()
.expressionHandler(securityExpressionHandler)
.antMatchers("/asset/**").access("permitAll")
.antMatchers("/ws/ssoEnabled").access("permitAll")
.antMatchers("/**").access("hasRole('ROLE_USER') or hasRole('ROLE_TOKEN_ACCESS')")
.and()
.httpBasic()
.authenticationEntryPoint(ajaxAwareLoginUrlAuthenticationEntryPoint)
.and()
// Handles unauthenticated requests, catching UserRedirectRequiredExceptions and redirecting to OAuth provider
.addFilterAfter(new OAuth2ClientContextFilter(), SecurityContextPersistenceFilter.class)
// Handles the oauth callback, exchanging the one-time code for a durable token
.addFilterAfter(openIdConnectFilter, OAuth2ClientContextFilter.class)
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/logincheck")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(ajaxAwareAuthenticationSuccessHandler)
.failureHandler(ajaxAwareAuthenticationFailureHandler)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.and()
.rememberMe()
.rememberMeServices(rememberMeServices)
// Even though this key has been added directly to the rememberMeServices instance, the RememberMeConfigurer
// can instantiate a new RememberMeServices with a made-up key if the same key is not provided.
.key("the key value")
;
// We do not configure a bean for the SessionAuthenticationStrategy. We want to use the Spring default strategy,
// which is configured by the above builder chain. In order to share the correct, configured instance with our
// custom OpenIdConnectFilter, we first tell the builder to perform the configuration (normally this would be
// done long after this method returns)...
http.getConfigurer(SessionManagementConfigurer.class).init(http);
// ... then we get the shared object by interface (SessionAuthenticationStrategy) class name...
final SessionAuthenticationStrategy sessionAuthenticationStrategy = http.getSharedObject(SessionAuthenticationStrategy.class);
// ... then set it in our custom filter.
openIdConnectFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
}
您会发现其中有多种身份验证机制。我们正在从表单登录迁移到Oauth登录,初始发行版中有一个功能标记。该标志运行得很好,除了在顶部的链接问题中描述的问题之外,该问题在翻转标志后会出现一段时间,然后似乎可以自行解决。
上面显示的配置是否足以满足@EnableOauth2Client
注释的文档说明?
或者我还需要对DelegationFilterProxy
做些什么?如果可以,怎么办?