Spring 安全 OAuth2 - @EnableOauth2Sso 但也接受令牌作为身份验证
Spring Security OAuth2 - @EnableOauth2Sso but accept tokens as authentication, too
我有一个应用程序在 WebSecurityConfigurerAdapter
上有 @EnableOAuth2Sso
添加 @EnableOAuth2Sso
后,应用程序将我重定向到授权服务器,并允许在此授权服务器登录后进行访问。我也想提供 API 访问权限,所以我希望应用程序能够通过 Authorization-Header
传递访问令牌来访问我的资源
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(<generated>)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$f0788cea$$FastClassBySpringCGLIB$e95689d.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)
起初我以为我在我的过滤器中做错了什么,但我最终得到了一个普通的过滤器 class 除了继续过滤器链之外什么也没做,但仍然有同样的错误。
所以我有两个问题:
- 为什么我会得到这个异常?
- 有没有办法在使用
@EnableOAuth2Sso
的应用程序中对端点进行令牌身份验证?
这是对您第一个问题的回答。您收到此异常是因为您试图在不指定顺序的情况下将过滤器添加到文件管理器链。
过滤器链由要添加的 fixed order. The exception is thrown in the check for the existence 个过滤器中的多个过滤器组成。
AbstractSecurityBuilder
里面的org.springframework.security.config.annotation.AlreadyBuiltException
里面发生异常的时候。因此,AbstractSecurityBuilder
内部发生的各种异常导致了这个不相关的异常。
添加过滤器的一种可能方法是使用
addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter)
或 HttpSecurity
的 addFilterAfter(Filter filter, Class<? extends Filter> afterFilter)
方法。
关于你的第二个问题,你应该提供更多信息。
出现异常的原因是 @jah 所说的过滤器排序。
为了实现请求的身份验证,我在 Authorization-Header 中包含一个访问令牌,我所做的是创建一个扩展 OAuth2AuthenticationProcessingFilter
的 class 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 上开了一个问题。我不确定这个解决方案是否可行,但我没有找到另一种选择。
我有一个应用程序在 WebSecurityConfigurerAdapter
@EnableOAuth2Sso
添加 @EnableOAuth2Sso
后,应用程序将我重定向到授权服务器,并允许在此授权服务器登录后进行访问。我也想提供 API 访问权限,所以我希望应用程序能够通过 Authorization-Header
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(<generated>)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$f0788cea$$FastClassBySpringCGLIB$e95689d.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)
起初我以为我在我的过滤器中做错了什么,但我最终得到了一个普通的过滤器 class 除了继续过滤器链之外什么也没做,但仍然有同样的错误。
所以我有两个问题:
- 为什么我会得到这个异常?
- 有没有办法在使用
@EnableOAuth2Sso
的应用程序中对端点进行令牌身份验证?
这是对您第一个问题的回答。您收到此异常是因为您试图在不指定顺序的情况下将过滤器添加到文件管理器链。
过滤器链由要添加的 fixed order. The exception is thrown in the check for the existence 个过滤器中的多个过滤器组成。
AbstractSecurityBuilder
里面的org.springframework.security.config.annotation.AlreadyBuiltException
里面发生异常的时候。因此,AbstractSecurityBuilder
内部发生的各种异常导致了这个不相关的异常。
添加过滤器的一种可能方法是使用
addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter)
或 HttpSecurity
的 addFilterAfter(Filter filter, Class<? extends Filter> afterFilter)
方法。
关于你的第二个问题,你应该提供更多信息。
出现异常的原因是 @jah 所说的过滤器排序。
为了实现请求的身份验证,我在 Authorization-Header 中包含一个访问令牌,我所做的是创建一个扩展 OAuth2AuthenticationProcessingFilter
的 class 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 上开了一个问题。我不确定这个解决方案是否可行,但我没有找到另一种选择。