Spring Security OAuth2 - @ EnableOauth2Sso,但也接受令牌作为身份验证

时间:2016-01-11 09:59:44

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

我的应用程序在@EnableOAuth2Sso

上有WebSecurityConfigurerAdapter

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

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
  3. 的应用程序中的端点进行令牌身份验证

2 个答案:

答案 0 :(得分:9)

异常的原因是像@jah这样的过滤器的排序。

我在Authorization-Header中实现对包含访问令牌的请求进行身份验证的方法是创建一个扩展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上打开了一个问题。我不确定这种解决方案是否可行,但我没有找到另一种替代方案。

答案 1 :(得分:2)

这是您第一个问题的答案。您收到此异常是因为您尝试在不指定顺序的情况下将过滤器添加到文件管理链。 过滤器链由fixed order中的多个过滤器组成。要添加的过滤器的check for the existence中会抛出异常。 当int stepLen = 10; // draw 10 pixels on each tick List<Point> SlowWay(List<Point> way) { List<Point> slow = new List<Point>(); for (int i = 1; i < way.Count; i++ ) { int dx = way[i].X - way[i - 1].X; int dy = way[i].Y - way[i - 1].Y; float len = (float)Math.Sqrt(dx*dx+dy*dy); int stepCount = (int)(len / stepLen); float stepX = dx / stepCount; float stepY = dy / stepCount; slow.Add(way[i - 1]); for (int s = 0; s < stepCount; s++) slow.Add(new Point((int)(way[i - 1].X + s * stepX), (int)(way[i - 1].Y + s * stepY))); } slow.Add(way[way.Count - 1]); return slow; } 内发生异常时,org.springframework.security.config.annotation.AlreadyBuiltException。因此AbstractSecurityBuilder内发生的各种异常导致了这种无关的异常。

添加过滤器的一种可能方法是使用 AbstractSecurityBuilder的{​​{1}}或addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter)方法{/ 1}}。

关于第二个问题,您应该提供更多信息。