java - Spring Security OAuth2 - @EnableOauth2Sso 但也接受 token 作为身份验证

标签 java spring spring-security spring-boot spring-security-oauth2

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

添加 @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)

起初我以为我在我的过滤器中做错了什么,但我最终得到了一个普通的过滤器类,除了继续过滤器链之外什么也没做,但仍然有同样的错误。

所以我有两个问题:

  1. 为什么会出现此异常?
  2. 有没有一种方法允许在使用 @EnableOAuth2Sso 的应用程序中对端点进行 token 身份验证?

最佳答案

异常的原因是过滤器的排序,如 @jah说。

为了实现请求的身份验证,在授权 header 中包含访问 token ,我所做的是创建一个扩展 OAuth2AuthenticationProcessingFilter 的类 ApiTokenAccessFilter。此过滤器采用 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 上开了一个问题.我不确定这个解决方案是否可行,但我没有找到另一种选择。

关于java - Spring Security OAuth2 - @EnableOauth2Sso 但也接受 token 作为身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34718586/

相关文章:

java - 如何在 Java 中生成正态累积分布?它的逆cdf?对数正态怎么样?

java - 使用 @DataJpaTest 的 Spring 测试无法使用 @Repository Autowiring 类(但接口(interface)存储库有效!)

java - 使用mockito初始化spring batch jobExecution

java - 错误 :org. postgresql.util.PSQLException :ERROR: column userinfo0_. dtype 不存在

java - Spring Batch 3.0.2 与 Spring Core 4.1.x 的集成 - 使用 @EnableBatchProcessing 的合适方法是什么?

java - spring security - 动态角色

java - Spring Security什么时候记得我处理cookie?

java - Java 中的公共(public)接口(interface)和已发布接口(interface)有什么区别?

java - 如何以编程方式设置 Spring Boot 的日志记录级别?

java - OAuth 资源所有者密码 Java