Spring boot 使用JWT的Spring安全性,如何从使用JwtAuthenticationFilter的身份验证中排除某些端点,如/login?

Spring boot 使用JWT的Spring安全性,如何从使用JwtAuthenticationFilter的身份验证中排除某些端点,如/login?,spring-boot,spring-security,jwt,Spring Boot,Spring Security,Jwt,我想将/login url从spring security的身份验证中排除。 我的配置类看起来像' @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

我想将/login url从spring security的身份验证中排除。 我的配置类看起来像'

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

    http.csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and().authorizeRequests().antMatchers("/v1/pricing/login").permitAll()
            .antMatchers("v1/pricing/**").authenticated().and()
    .addFilterBefore(corsFilter,UsernamePasswordAuthenticationFilter.class)
    .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

}


 @Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/v1/pricing/login");

}
JwtAuthenticationFilter看起来像 -注释了异常部分,因为它也开始在登录时抛出异常

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {


private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

@Autowired
JwtTokenProvider jwtTokenProvider;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {


    String jwt = getJwtFromRequest(request);

    if (StringUtils.hasText(jwt) && jwtTokenProvider.validateToken(jwt)) {

        String[] userInfo = jwtTokenProvider.getUserDetailsFromJWT(jwt);
        UserDetails userDetails = new UserPrincipal(Long.parseLong(userInfo[0]), userInfo[1], userInfo[2], null,
                userInfo[3]);
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(userDetails, null, null);
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

    }


    filterChain.doFilter(request, response);

}

private String getJwtFromRequest(HttpServletRequest request) {

    String token = request.getHeader("Authorization");
    if (StringUtils.hasText(token)) {
        return token;
    } /*else {
        throw new AuthenticationServiceException("Authorization header cannot be blank!");
    }*/
    return null;
}
}


任何带有/v1/pricing/login的请求仍然会转到JWtAuthentication筛选器并失败

JwtTokenAuthenticationProcessingFilter筛选器配置为跳过以下端点:/api/auth/login和/api/auth/token。这是通过RequestMatcher的SkipPathRequestMatcher实现实现的

public class SkipPathRequestMatcher implements RequestMatcher {
    private OrRequestMatcher matchers;
    private RequestMatcher processingMatcher;

    public SkipPathRequestMatcher(List<String> pathsToSkip, String processingPath) {
        Assert.notNull(pathsToSkip);
        List<RequestMatcher> m = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList());
        matchers = new OrRequestMatcher(m);
        processingMatcher = new AntPathRequestMatcher(processingPath);
    }

    @Override
    public boolean matches(HttpServletRequest request) {
        if (matchers.matches(request)) {
            return false;
        }
        return processingMatcher.matches(request) ? true : false;
    }
}
公共类SkipPathRequestMatcher实现RequestMatcher{
私人或请求匹配者;
私有请求匹配器处理匹配器;
公共SkipPathRequestMatcher(列表路径跳过,字符串处理路径){
Assert.notNull(路径跳过);
List m=pathsToSkip.stream().map(路径->新建AntPathRequestMatcher(路径)).collect(收集器.toList());
匹配器=新匹配器或请求匹配器(m);
processingMatcher=新的AntPathRequestMatcher(processingPath);
}
@凌驾
公共布尔匹配(HttpServletRequest){
if(matchers.matches(请求)){
返回false;
}
返回processingMatcher.matches(请求)?true:false;
}
}
然后打电话:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {  
    public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
    public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
    public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
    public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";

    protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
        List<String> pathsToSkip = Arrays.asList(TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT);
        SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
        JwtTokenAuthenticationProcessingFilter filter 
            = new JwtTokenAuthenticationProcessingFilter(failureHandler, tokenExtractor, matcher);
        filter.setAuthenticationManager(this.authenticationManager);
        return filter;
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(ajaxAuthenticationProvider);
        auth.authenticationProvider(jwtAuthenticationProvider);
    }

    @Bean
    protected BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable() // We don't need CSRF for JWT based authentication
        .exceptionHandling()
        .authenticationEntryPoint(this.authenticationEntryPoint)

        .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

        .and()
            .authorizeRequests()
                .antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
                .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
                .antMatchers("/console").permitAll() // H2 Console Dash-board - only for testing
        .and()
            .authorizeRequests()
                .antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points
        .and()
            .addFilterBefore(buildAjaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
@配置
@启用Web安全性
公共类WebSecurityConfig扩展了WebSecurityConfigureAdapter{
公共静态最终字符串JWT_TOKEN_HEADER_PARAM=“X-Authorization”;
公共静态最终字符串形式基于登录登录条目点=“/api/auth/LOGIN”;
公共静态最终字符串标记基于身份验证入口点=“/api/**”;
公共静态最终字符串标记\u刷新\u条目\u点=“/api/auth/TOKEN”;
受保护的JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter()引发异常{
List pathsToSkip=Arrays.asList(令牌\刷新\条目\点,基于表单\登录\条目\点);
SkipPathRequestMatcher matcher=新的SkipPathRequestMatcher(路径跳过,基于令牌的认证入口点);
JwtTokenAuthenticationProcessingFilter过滤器
=新的JwtTokenAuthenticationProcessingFilter(failureHandler、tokenExtractor、matcher);
filter.setAuthenticationManager(this.authenticationManager);
回流过滤器;
}
@豆子
@凌驾
公共AuthenticationManager authenticationManagerBean()引发异常{
返回super.authenticationManagerBean();
}
@凌驾
受保护的无效配置(AuthenticationManagerBuilder身份验证){
authenticationProvider(ajaxAuthenticationProvider);
authenticationProvider(jwtAuthenticationProvider);
}
@豆子
受保护的BCryptPasswordEncoder passwordEncoder(){
返回新的BCryptPasswordEncoder();
}
@凌驾
受保护的无效配置(HttpSecurity http)引发异常{
http
.csrf().disable()//基于JWT的身份验证不需要csrf
.例外处理()
.authenticationEntryPoint(此.authenticationEntryPoint)
.及()
.会议管理()
.sessionCreationPolicy(sessionCreationPolicy.STATELESS)
.及()
.授权请求()
.antMatchers(基于表单的登录入口点)。permitAll()//登录终点
.antMatchers(令牌\刷新\入口\点).permitAll()//令牌刷新端点
.antMatchers(“/console”).permitAll()//H2控制台仪表板-仅用于测试
.及()
.授权请求()
.antMatchers(基于令牌的认证入口点)。authenticated()//受保护的API端点
.及()
.addFilterBefore(buildAjaxLoginProcessingFilter(),UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(),UsernamePasswordAuthenticationFilter.class);
}
}
web.ignering()。antMatchers(“/v1/pricing/login”)是否应跳过此url的筛选器?这不是web.ignoring()的目的吗?可能是重复的