简体   繁体   中英

unauthorized request are always allowed in springboot using jwt

I have a project which I had enabled jwt for authorization on it. The problem is that whenever I send an empty header request or expired authorization code in the header it doesn't send me the unauthorized error, it shows in the log that the token is not valid but allows the request to continue working. this is my configuration code:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    @Autowired
    private UserDetailsService jwtUserDetailsService;
    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(BCryptVersion.$2Y);
    }

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

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()

                .authorizeRequests().antMatchers("/authenticate","/user","/swagger-ui.html","/swagger-ui/**"
                ,"/v3/api-docs/**").permitAll().

                anyRequest().authenticated().and().

                exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()

                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

        httpSecurity.logout().logoutSuccessUrl("/authenticate").logoutUrl("/logout").permitAll();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers(String.valueOf(HttpMethod.OPTIONS), "/**");
        // ignore swagger
        web.ignoring().mvcMatchers("/swagger-ui.html/**", "/configuration/**", "/swagger-resources/**", "/v2/api-docs");
    }
}

and this is my jwt request filter:

@Component
public class JwtRequestFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    private JwtTokenUtil jwtTokenUtil;

    public JwtRequestFilter(JwtTokenUtil jwtTokenUtil) {
        this.jwtTokenUtil = jwtTokenUtil;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        final String requestTokenHeader = request.getHeader("Authorization");
        String username = null;
        String jwtToken = null;
// JWT Token is in the form "Bearer token". Remove Bearer word and get
// only the Token
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {

            jwtToken = requestTokenHeader.substring(7);

            try {

                username = jwtTokenUtil.getUsernameFromToken(jwtToken);

            } catch (IllegalArgumentException e) {

                System.out.println("Unable to get JWT Token");

            } catch (ExpiredJwtException e) {

                System.out.println("JWT Token has expired");

            }

        }
        else if (requestTokenHeader == null){

            logger.info("Does not provide Authorization Header");

        }
        else if (!requestTokenHeader.startsWith("Bearer ")){
            logger.warn("JWT Token does not begin with Bearer");
        }

// Once we get the token validate it.
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
// if token is valid configure Spring Security to manually set
// authentication
            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the
// Spring Security Configurations successfully.
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}

and finally here is JwtAuthenticationEntryPoint:

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
    private static final long serialVersionUID = -7858869558953243875L;
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException) throws IOException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}

and this is the log that shows I did not send any token in header, but it allows the request: 在此处输入图像描述

any idea that what should I do? for further information, I should say that this code was working but stopped working after a while and I didn't find any reason because I had no changes in these files for months.

The problem is the misconfiguration at this line

web.ignoring().mvcMatchers(String.valueOf(HttpMethod.OPTIONS), "/**");

It should be

web.ignoring().mvcMatchers(HttpMethod.OPTIONS, "/**");

As you might have noticed now that your configuration is actually ignoring all request paths from Spring Security filters. That is the reason that all unauthorized requests (which you expect) are allowed now.

You are missing addFilterAfter and also update your code as below.

  @Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity.csrf().disable()

            .authorizeRequests().antMatchers("/authenticate","/user","/swagger-ui.html","/swagger-ui/**"
            ,"/v3/api-docs/**").permitAll().

            anyRequest().authenticated().and().

            exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()

            .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

   .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class).logout().logoutSuccessUrl("/authenticate").logoutUrl("/logout").permitAll();
}

Please refer https://github.com/techiesantosh/taskmanager-service/blob/develop/src/main/java/com/web/taskmanager/config/TaskConfig.java

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