我有一个在@EnableOAuth2Sso上具有WebSecurityConfigurerAdapter的应用程序

添加@EnableOAuth2Sso后,应用程序将我重定向到授权服务器,并在登录到该授权服务器后允许访问。我也想提供API访问权限,所以我希望应用程序能够通过Authorization-Header传递一个访问 token 来访问我的资源。

Authorization: bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...

我通过发现与@EnableOAuth2Sso一起使用的身份验证过滤器进行了调试,未检查Authorization-Header值。

之后,我尝试创建一个自定义过滤器并将此过滤器添加到安全配置中
@Override
public void configure(HttpSecurity http) throws Exception {
  http.addFilter(myCustomFilter)
    ...;
}

但是现在我得到以下异常:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 26 more
Caused by: org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
    at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:44)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:105)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$f0788cea.CGLIB$springSecurityFilterChain$5(<generated>)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$f0788cea$$FastClassBySpringCGLIB$$7e95689d.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$f0788cea.springSecurityFilterChain(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)

起初,我以为自己在过滤器内做错了什么,但最终我得到了一个普通的过滤器类,除了继续执行过滤器链之外,别无其他选择,并且仍然有相同的错误。

所以我有两个问题:
  • 为什么会出现此异常?
  • 在使用@EnableOAuth2Sso的应用程序中,是否可以对端点进行 token 身份验证?
  • 最佳答案

    出现异常的原因是像@jah所说的过滤器的顺序。

    为了实现对请求的身份验证(在Authorization-Header中包含访问 token ),我要做的是创建一个ApiTokenAccessFilter类,该类扩展了OAuth2AuthenticationProcessingFilter。此过滤器采用ResourceServerTokenServices构造函数参数,并将无状态标志设置为false。

    public class ApiTokenAccessFilter extends OAuth2AuthenticationProcessingFilter {
    
      public ApiTokenAccessFilter(ResourceServerTokenServices resourceServerTokenServices) {
    
        super();
        setStateless(false);
        setAuthenticationManager(oauthAuthenticationManager(resourceServerTokenServices));
      }
    
      private AuthenticationManager oauthAuthenticationManager(ResourceServerTokenServices tokenServices) {
    
        OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager();
    
        oauthAuthenticationManager.setResourceId("oauth2-resource");
        oauthAuthenticationManager.setTokenServices(tokenServices);
        oauthAuthenticationManager.setClientDetailsService(null);
    
        return oauthAuthenticationManager;
      }
    }
    

    在我的安全配置中,我使用了此过滤器,如下所示:
    @Configuration
    @EnableOAuth2Sso
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
      @Autowired
      private ResourceServerTokenServices tokenServices;
    
      @Override
      public void configure(HttpSecurity http) throws Exception {
    
        http.authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .addFilterBefore(new ApiTokenAccessFilter(tokenServices), AbstractPreAuthenticatedProcessingFilter.class);
      }
    }
    

    我认为这可能会更容易,所以我在spring-security-oauth Github repo上打开了一个问题。我不确定该解决方案是否可行,但是我没有找到其他选择。

    09-30 12:43