简体   繁体   中英

Gettig error while trying to access unsecured route

I am using spring security in my java project to secure web services. All my web services are secured here are filter chain configuiration that i use:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .cors().and()
            .csrf().disable()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .addFilter(new JwtEmailAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
            .addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig),JwtEmailAndPasswordAuthenticationFilter.class)
            .authorizeRequests()
            .anyRequest()
            .authenticated();
}
    

Now I have a requirement to create one web service that will be accessible to everybody. For this purpose I add this row:

.and().authorizeRequests().antMatchers("/auth/reset").permitAll()

To chained filers and it looks like that:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .cors().and()
            .csrf().disable()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .addFilter(new JwtEmailAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
            .addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig),JwtEmailAndPasswordAuthenticationFilter.class)
            .authorizeRequests()
            .and().authorizeRequests().antMatchers("/auth/reset").permitAll()
            .anyRequest()
            .authenticated();
}

After adding the row above I get exception JWT not found, it comes from this JwtTokenVerifier bean which is fired by addFilterAfter.

My question is how can I prevent trigger addFilterAfter or any other filter that is needed only for the secured routes in case of the request for an unsecured web service?

UPDATE

Here is definition of JwtTokenVerifier bean:

public class JwtTokenVerifier extends OncePerRequestFilter {
    private final SecretKey secretKey;
    private final JwtConfig jwtConfig;

    public JwtTokenVerifier(SecretKey secretKey,
                            JwtConfig jwtConfig) {
        this.secretKey = secretKey;
        this.jwtConfig = jwtConfig;
    }

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

        try {
            
            String authorizationHeader = request.getHeader(jwtConfig.getAuthorizationHeader());

            if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
                filterChain.doFilter(request, response);
                return;
            }

            String token = authorizationHeader.replace(jwtConfig.getTokenPrefix(), "");

            try {

                Jws<Claims> claimsJws = Jwts.parser()
                        .setSigningKey(secretKey)
                        .parseClaimsJws(token);

                Claims body = claimsJws.getBody();

                String email = body.getSubject();

                var authorities = (List<Map<String, String>>) body.get("authorities");

                Set<SimpleGrantedAuthority> simpleGrantedAuthorities = authorities.stream()
                        .map(m -> new SimpleGrantedAuthority(m.get("authority")))
                        .collect(Collectors.toSet());

                Authentication authentication = new UsernamePasswordAuthenticationToken(
                        email,
                        null,
                        simpleGrantedAuthorities
                );

                SecurityContextHolder.getContext().setAuthentication(authentication);

            } catch (JwtException e) {
                throw new IllegalStateException(String.format("Token %s cannot be trusted", token));
            }

            filterChain.doFilter(request, response);
        } catch (JwtException e) {
        throw e;
    }
  }
}   

I realize you didn't ask this, but I'd first recommend that you use Spring Security's built-in JWT support instead of building your own. Security is hard, and using vetted support is likely more secure.

Regarding your question about having separate auth mechanisms for separate endpoints, you can instead publish two filter chains, one for open endpoints and one for token-based endpoints like so:

@Bean
@Order(0)
SecurityFilterChain open(HttpSecurity http) {
    http
        .requestMatchers((requests) -> requests.antMatchers("/auth/reset"))
        .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll());

    return http.build();
}

@Bean
SecurityFilterChain tokenBased(HttpSecurity http) {
    http
        .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
        .addFilter(...)
        .addFilterAfter(...);

    return http.build();
}

Have you tried something like that:

 .and().authorizeRequests().antMatchers("...").permitAll().and().addFilter(...).authorizeRequests().anyRequest().authenticated().and()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM