spring过滤器适用于所有api urls错误

时间:2015-05-17 05:14:51

标签: spring-security spring-java-config

我是Spring安全新手,问题是过滤器应用于所有请求URL i-e。 /api/user/signup。我想排除/api/user/signup路径以通过过滤器。我甚至尝试过跟随

web.ignoring()
            .antMatchers("/api/user/**")
            .antMatchers("/api/user/signup")

但过滤器再次应用于它。过滤器需要authkey令牌和注册请求 万分没有令牌。当它没有找到令牌时它将通过异常。以下是spring security java config class

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
AuthenticationTokenProcessingFilter authenticationTokenFilter;
@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring()
    .antMatchers("/api/user/**")
    .antMatchers("/api/user/signup")

    ;
}
@Override
protected void configure(HttpSecurity http) throws Exception {


    http
    .csrf().disable()
    .authorizeRequests()   

    //allow anonymous POSTs to login
    .antMatchers("/api/user/signup").permitAll()

    //allow anonymous GETs to API
    .antMatchers(HttpMethod.GET, "/api/**").permitAll()
    .and()
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)     
    .and()
     .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)    
      ;
}

这是我的令牌过滤器类

@Component
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {

  //  @Autowired UserService userService;
   @Autowired 
   TokenHandler tokenUtils;
   @Autowired
    AuthenticationManager authManager;

    public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) {
        this.authManager = authManager;
    }

    public AuthenticationTokenProcessingFilter() {
        super();
        // TODO Auto-generated constructor stub
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        @SuppressWarnings("unchecked")

        HttpServletRequest req = (HttpServletRequest) request;

        SecurityContext context = SecurityContextHolder.getContext();

        if (context.getAuthentication() != null && context.getAuthentication().isAuthenticated()) {
            // do nothing
        }else {

            //System.out.println("Not Authenticated");
        if(req != null && req.getHeader("authKey") != null && req.getHeader("authKey").length() >0 ) {
            String token = req.getHeader("authKey"); 
           System.out.println("Found Token:"+req.getHeader("authKey"));
            // validate the token
            User userDetails = tokenUtils.parseUserFromToken(token);

                     List<GrantedAuthority> grantedAuths = new ArrayList<>();
                     grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
                     Authentication  authentication = 
                        new UsernamePasswordAuthenticationToken(userDetails.getEmail(), userDetails.getPassword(),grantedAuths);

                // set the authentication into the SecurityContext

                SecurityContextHolder.getContext().setAuthentication(authentication);         


           System.out.println("Is Authenticated:?"+  context.getAuthentication().isAuthenticated());
        // continue thru the filter chain
           chain.doFilter(request, response);
           System.out.println(" request is delegeted");
        }else{ 

                // Do your business stuff here for all paths other than /specialpath.
                System.out.println(" Token Not Found");
                throw new ServletException("Token not found in Request");           

        }

    }
}

以下是/api/user/signup到来时的错误日志

Token Not Found
2015-05-17 09:38:36.742 ERROR 5096 --- [nio-8090-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Token not found in Request] with root cause

javax.servlet.ServletException: Token not found in Request
    at com.bitsparlour.sadaf.cloud.application.AuthenticationTokenProcessingFilter.doFilter(AuthenticationTokenProcessingFilter.java:93)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
    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)

3 个答案:

答案 0 :(得分:0)

其中一个解决方案是根据传入的URL跳过过滤器逻辑。 就在这一行之后:

HttpServletRequest req = (HttpServletRequest) request;

在您doFilter的方法AuthenticationTokenProcessingFilter中添加此代码:

if (new AntPathRequestMatcher("/api/user/signup").matches(req))) {
    chain.doFilter(request, response);
    return;
}

当然,对doFilter方法中的网址进行硬编码并不是一个好习惯 - 您可以通过SecurityConfig.configure方法将该网址传递给过滤器。此外,new AntPathRequestMatcher可以进行优化 - 只需创建一次并放入字段变量。

答案 1 :(得分:0)

解决方案是模仿具有多个where col1 is not null or col2 is not null or col3 is not null) 块的良好旧命名空间方式。使用Java配置,您还可以拥有多个扩展<http ...>的类。 Spring Security Reference Manual有一个example。摘录:

WebSecurityConfigurerAdapter

注意:

  1. 正常配置@EnableWebSecurity public class MultiHttpSecurityConfig { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) { 1 ... } @Configuration @Order(1) 2 public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/api/**") 3 ... } } @Configuration 4 public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .formLogin() ... } } }
  2. 创建包含Authentication的{​​{1}}实例,以指定应首先考虑WebSecurityConfigurerAdapter
  3. @Order声明此WebSecurityConfigurerAdapter仅适用于以http.antMatcher开头的网址
  4. 创建HttpSecurity的另一个实例。如果网址不以/api/开头,则会使用此配置(默认为WebSecurityConfigurerAdapter无效)

答案 2 :(得分:0)

通过使用&#39; @Component&#39;注释您的过滤器,您告诉Spring将其添加到嵌入式容器中。

  

任何Servlet,Filter或Servlet *作为Spring bean的监听器实例将在嵌入式容器中注册。如果要在配置期间引用application.properties中的值,这可能特别方便。

所以.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)这条线没有影响。

要解决此问题,请删除@Component和@Autowired并构建您自己的实例,并且不要将其设为bean。