Spring Boot和Spring Security过滤器未过滤正确的请求

时间:2019-07-08 16:27:23

标签: spring spring-boot spring-security

我有一个弹簧靴和弹簧安全服务。 我扩展了WebSecurityConfigurerAdapter类并覆盖了configure方法。但是不知何故,它无法过滤正确的请求。

我的网址类似于-

localhost:8080/album/private/v1/getAlbumsByVendorId?vendorId=1
 localhost:8080/vendor/private/v1/getVendor?vendorId=1

,还有一些我不想进行身份验证的URL,例如下面的url。

localhost:8080/category/v1/getCategory

仅在URL包含私人身份时才想进行身份验证。 但是似乎我的过滤器正在为所有请求调用。 .antMatchers("/**/private/**")

中有问题吗

注意-到目前为止,我没有任何上下文路径。 添加了类。 控制器只是一个虚拟测试控制器。

@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();
    }

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

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
        .csrf().disable()
        .cors().disable()
        .authorizeRequests()
        .antMatchers("/authenticate").permitAll()
        .antMatchers("/**/private/**").authenticated()
        .anyRequest().authenticated()
        .and()
        .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
        .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
    }
}


    @Component
    public class JWTAuthenticationFilter extends OncePerRequestFilter {

        @Autowired
        private JwtUserDetailsService jwtUserDetailsService;

        @Autowired
        private 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 {
                logger.warn("JWT Token does not begin with Bearer String");
            }

            //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);
        }

    }



@RestController
@CrossOrigin()
public class HelloWorldController {

    @RequestMapping({ "/hello" })
    public String hello() {
        return "Hello World";
    }

    @RequestMapping({ "/private/test" })
    public String hello2() {
        return "Hello World-test";
    }

    @RequestMapping({ "/v1/private/test" })
    public String hello3() {
        return "Hello World-test-v1";
    }

    @RequestMapping({ "/v1/public/test" })
    public String hello4() {
        return "Hello World-test-v1-public";
    }

}

1 个答案:

答案 0 :(得分:0)

默认情况下,当Spring Security位于类路径上时,Spring Boot将保护所有端点。我们需要显式添加排除所有其他端点而无需身份验证的排除。考虑更改为.anyRequest().permitAll(),  这意味着除/**/private/**以外的每个请求都可以被所有人访问。换句话说,该过滤器将仅应用于/**/private/**

Git Link

方法1(简洁方式)

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable()
        .cors().disable()
        .authorizeRequests()
            .antMatchers("/authenticate").permitAll()
            .antMatchers("/**/private/**").authenticated()
            .anyRequest().permitAll()
            .and()
        .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
        .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
    }

方法2:仅当请求来自 / private / (不是理想方式)

时,才检查令牌

JwtAuthenticationEntryPoint.java

@Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException {

        System.out.println("Entry Request: "+request.getRequestURI());
        System.out.println("Entry Contain: "+request.getRequestURI().contains("private"));
        if(request.getRequestURI().contains("private")==true) 
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");

    } 

JwtRequestFilter.java

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

        final String requestTokenHeader = request.getHeader("Authorization");
        System.out.println("JWT Request: "+request.getRequestURI());
        System.out.println("JWT Contain: "+request.getRequestURI().contains("private"));
        String username = null;
        String jwtToken = null;
        //Remove comment for second approach
        if(request.getRequestURI().contains("private")==false)
        {
            System.out.println("Do Noting, Permit It");
            chain.doFilter(request, response);
        }
        else 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 {
            logger.warn("JWT Token does not begin with Bearer String");
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);

            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }

http://localhost:8080/v1/private/test **401**

http://localhost:8080/v1/private/test

http://localhost:8080/v1/public/test **200**

http://localhost:8080/v1/public/test