【问题标题】:Add nested custom filters in Spring Security filterchain在 Spring Security 过滤器链中添加嵌套的自定义过滤器
【发布时间】:2019-12-25 20:02:40
【问题描述】:

我创建了两个过滤器来使用 JWT 令牌执行身份验证。 我想在第一个中处理 JWT 异常:exceptionTokenVerificationHandlerFilter 并检查第二个中是否一切正常:jwtTokenFilter。 如果由于过期日期而导致身份验证失败,则该过程返回到第一个过滤器并向前端发送响应,并带有拒绝访问消息。

我将此答案用作对我的应用程序的支持: https://github.com/szerhusenBC/jwt-spring-security-demo/issues/63#issuecomment-377012514

我的课:

WebSecurityConfig

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .httpBasic().disable()
            .addFilterBefore(exceptionTokenVerificationHandlerFilter, JwtTokenFilter.class)
            .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .cors().and()
            .csrf().disable()
            .authorizeRequests() // .antMatchers("/**")
                .antMatchers("/login/**", "/register/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")      
                .anyRequest().authenticated()
                .and()
            //.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
            .addFilterAt(customUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)    
            /*.formLogin()
                .loginPage("http://localhost:4200/login")//.failureUrl("/login-error")
                .loginProcessingUrl("/login") 
                .usernameParameter("email")
                .successHandler(customAuthenticationSuccessHandler)
                .and()*/
            .logout() 
                .permitAll();
    }    

ExceptionTokenVerificationHandlerFilter

package app.shellx.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.jsonwebtoken.JwtException;

@Configuration
public class ExceptionTokenVerificationHandlerFilter extends OncePerRequestFilter {

    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            filterChain.doFilter(request, response);
        } catch (JwtException e) {

            String message;

            switch(e.getClass().getName()) {
            case "ExpiredJwtException":
                message = "token-expired";
            break;
            default:
                message = e.getMessage();
            break;
            }

            response.setStatus(HttpStatus.BAD_REQUEST.value());
            response.getWriter().write(convertObjectToJson(message));
    }
}

    private String convertObjectToJson(Object object) throws JsonProcessingException {
        if (object == null) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(object);
    }

}

JwtTokenFilter

package app.shellx.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

@Configuration
public class JwtTokenFilter extends GenericFilterBean {

    private JwtTokenProvider jwtTokenProvider;

    public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
        String token = jwtTokenProvider.resolveToken((HttpServletRequest) req);
        if (token != null && jwtTokenProvider.validateToken(token)) {
            Authentication auth = token != null ? jwtTokenProvider.getAuthentication(token) : null;
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
        filterChain.doFilter(req, res);
    }
}

那么我可以在过滤器链中一个接一个地添加两个自定义过滤器吗?

我现在从编译器收到以下错误消息:

原因:java.lang.IllegalArgumentException:未注册Filter类app.shellx.security.JwtTokenFilter后无法注册

【问题讨论】:

  • 什么是 JSON Web Token Token,为什么在代码中重复单词 token 很重要?
  • @Tom 无缘无故,我只是习惯了这样命名

标签: java spring spring-security spring-filter


【解决方案1】:

我通过在两个过滤器类上使用@Order 注释解决了自己的问题。 @Order(1)ExceptionTokenVerificationHandlerFilter@Order(2)JwtTokenFilter

我还将第一个 addFilterBefore() 的第二个参数更改为 UsernamePasswordAuthenticationFilter.class 看来我们不能把自定义过滤器作为这个方法的第二个参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-27
    • 2020-11-04
    • 2011-08-23
    • 2014-07-28
    • 1970-01-01
    • 2016-03-08
    • 2013-07-22
    • 1970-01-01
    相关资源
    最近更新 更多