Spring Security自定义过滤器创建无限循环

时间:2014-08-22 23:22:58

标签: spring authentication spring-security spring-boot

依赖项:Spring Boot 1.1.5.RELEASE,Spring 4.0.6.RELEASE,Spring Security 3.2.4.RELEASE

问题:我正在创建一个自定义过滤器,该过滤器基于请求中的令牌查询提供程序以对用户进行身份验证。自定义过滤器代码和配置为here。正如您所看到的,我已经尽可能地禁用以查明问题。启用调试显示我

Security filter chain: [
  WebAsyncManagerIntegrationFilter
  CustomAuthenticationFilter
  SecurityContextPersistenceFilter
  SecurityContextHolderAwareRequestFilter
  FilterSecurityInterceptor
]

另一件事是日志告诉我用户已通过身份验证。

当查询应用程序时发生无限循环并最终请求返回,curl说它不能遵循那么多重定向,邮递员说服务器有问题。我已阅读一些关于无限循环的帖子,因为登录页面是安全的。在我的情况下,我不想在我的应用程序中启用任何登录。如果我无法对用户进行身份验证,则会返回401/403状态。请记住,该应用程序充当客户端请求的身份验证代理,但它本身不是客户端。我要求帮助确定当前配置中的错误,或确认我的方法不起作用?无论哪种方式,都要提前感谢您的帮助。

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig
    extends WebSecurityConfigurerAdapter {
    @Value("${oauth.check_token.url:http://localhost:3030/oauth/token/info}")
    private String checkTokenUrl;

    @Autowired @Qualifier("restTemplate")
    private RestOperations authRestTemplate;

[编辑] 如果我不使用邮递员,我发现无限循环停止,如果我不告诉curl遵循重定向。下面是我在SecurityContextPersistentFilter之前放置CustomAuthenticationFilter时获得的完整日志。

************************************************************

    Request received for GET '/test-oauth':

    org.apache.catalina.connector.RequestFacade@35a0339c

    servletPath:/test-oauth
    pathInfo:null
    headers: 
    user-agent: curl/7.30.0
    host: localhost:8081
    accept: */*
    authorization: Bearer 8f58520f137b25b096b48a67135c5b9b294892a8c712d5c2bcb8d90ab9f6efd0


    Security filter chain: [
      WebAsyncManagerIntegrationFilter
      CustomAuthenticationFilter
      SecurityContextPersistenceFilter
      SecurityContextHolderAwareRequestFilter
      FilterSecurityInterceptor
    ]


    ************************************************************


    2014-08-23 18:54:39.453 DEBUG --- [nio-8081-exec-1] CustomAuthenticationFilter : Request is to process authentication
    2014-08-23 18:54:39.453 DEBUG --- [nio-8081-exec-1] CustomAuthenticationFilter : Attempting to authenticate: Bearer 8f58520f137b25b096b48a67135c5b9b294892a8c712d5c2bcb8d90ab9f6efd0
    2014-08-23 18:54:39.569 DEBUG --- [nio-8081-exec-1] CustomAuthenticationFilter : Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@93e3eff0: Principal: com.shift.sysops.auth.AuthSSOUser@f02988d6: Username: username; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER

如果我将自定义过滤器放在任何其他位置,则会抛出NPE,因为SecurityContextPersistenceFilter中的SecurityContextRepository为null。

2014-08-23 18:41:50.060 ERROR --- [nio-8081-exec-1] [dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

java.lang.NullPointerException: null
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:70)
    at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:59)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:89)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1720)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1679)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

2 个答案:

答案 0 :(得分:3)

据我所知,您有以下用例:

  1. 用户通过某些第三方应用(即不是您的应用)进行身份验证

  2. 用户访问您的应用后,您会获得auth标头并检查是否     用户是否经过身份验证。

  3. 如果他经过身份验证,则会获取         他的权限,细节等,并允许他访问你的         应用
  4. 如果未经过身份验证,则会发送401错误响应。
  5. 对于此用例,最好扩展AbstractPreAuthenticatedProcessingFilter。

    1. 您可以通过扩展来定义自定义预授权过滤器 AbstractPreAuthenticatedProcessingFilter。
    2. 在自定义过滤器中,您需要覆盖两个方法getPreAuthenticatedPrincipal()和getPreAuthenticatedCredentials()
    3. 在getPreAuthenticatedPrincipal()中,您可以检查请求中是否存在auth标头,如果存在则返回标头名称作为主体和标头值在凭证中
    4. 使用PreAuthenticatedAuthenticationProvider并提供自定义preAuthenticatedUserDetailsS​​ervice(通过扩展AuthenticationUserDetailsS​​ervice)以检查auth令牌是否有效,如果其有效也获取授权权限,则抛出AuthenticationException,如BadCredentialsException
    5. 创建实现AuthenticationEntryPoint的自定义AuthenticationEntryPoint,并覆盖begin方法以返回401响应。
    6. 如果存在有效的auth头,pre-auth过滤器将在springSecurityContext中设置经过身份验证的用户,如果auth头丢失/无效,将返回402错误响应。

      希望它有所帮助。

答案 1 :(得分:1)

我提出了两个满足我用例的解决方案。如果你遇到这个帖子有更好的答案,请分享。

  1. Override AnonymousAuthenticationFilter
  2. Extend AbstractAutenticationProcessingFilter