【问题标题】:Custom exception is not working in filter using spring boot and spring security自定义异常在使用 spring boot 和 spring security 的过滤器中不起作用
【发布时间】:2020-09-11 04:09:59
【问题描述】:

我正在使用 Spring Boot 和 Spring Security 创建具有 JWT 令牌基础安全性的 rest API。我想在令牌无效时抛出自定义异常。这样我就创建了自定义异常类,并且每当我抛出该异常时,每次都会在邮递员中得到空白响应。

我想扔这个

 if (header == null || !header.startsWith("Bearer")) {
    throw new JwtTokenMissingException("No JWT token found in the request headers");
  }

因为我发送的令牌没有 Bearer 关键字。它在控制台中打印,但不在邮递员中。

邮递员每次都回复空白

JwtAuthenticationEntryPoint 类

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable[!
    private static final long serialVersionUID = 1L;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}

WebSecurityConfig 类

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

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

    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
    }

    @Bean
    public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
        return new JwtAuthenticationFilter();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests().antMatchers("/login").permitAll().anyRequest()
                .authenticated().and().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public BCryptPasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }

}

JwtAuthenticationFilter 类

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwtTokenPrefix}")
    private String tokenPrefix;

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

        String header = req.getHeader("Authorization");
        String username = null;
        String authToken = null;

        if (header == null || !header.startsWith("Bearer")) {
            throw new JwtTokenMissingException("No JWT token found in the request headers");
        }

        authToken = header.replace(tokenPrefix, "");
        jwtTokenUtil.validateJwtToken(authToken);
        username = jwtTokenUtil.getUserNameFromJwtToken(authToken);
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
                    null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(req));
            logger.info("authenticated user " + username + ", setting security context");
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        chain.doFilter(req, res);
    }
}

JwtTokenUtil 类

@Component
public class JwtTokenUtil implements Serializable {

    private static final long serialVersionUID = 1L;

    @Value("${jwtSecret}")
    private String jwtSecret;

    @Value("${jwtExpirationInMs}")
    private int jwtExpirationMs;

    public String generateJwtToken(String username) {

        return Jwts.builder()
                .setSubject((username))
                .setIssuedAt(new Date())
                .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
    }

    public String getUserNameFromJwtToken(String token) {
        return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
    }

    public void validateJwtToken(String authToken) throws JwtTokenMalformedException, JwtTokenMissingException {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
        } catch (SignatureException e) {
            throw new JwtTokenMalformedException("Invalid JWT signature");
        } catch (MalformedJwtException e) {
            throw new JwtTokenMalformedException("Invalid JWT token");
        } catch (ExpiredJwtException e) {
            throw new JwtTokenMalformedException("Expired JWT token");
        } catch (UnsupportedJwtException e) {
            throw new JwtTokenMalformedException("Unsupported JWT token");
        } catch (IllegalArgumentException e) {
            throw new JwtTokenMissingException("JWT claims string is empty.");
        }
    }

}

自定义异常类

public class JwtTokenMalformedException extends AuthenticationException {
    private static final long serialVersionUID = 1L;

    public JwtTokenMalformedException(String msg) {
        super(msg);
    }
}


public class JwtTokenMissingException extends AuthenticationException {
    private static final long serialVersionUID = 1L;

    public JwtTokenMissingException(String msg) {
        super(msg);
    }
}

【问题讨论】:

  • 如果你想在响应体中看到一些东西,那么你应该在处理异常时在响应体中写一些东西。请参考此页面:docs.oracle.com/javaee/6/api/javax/servlet/http/…。当您的消息被忽略时,您可能会遇到这种情况。
  • 是的,它的工作。在响应正文中更改了一些代码之后它工作正常

标签: java spring-boot exception spring-security


【解决方案1】:

试试下面的代码:

String jwtToken = null;

if(headers.containKey("Authorization")){
   jwtToken = headers.get("Authorization");
}

if (jwtToken == null || !jwtToken.startsWith("Bearer")) {
    throw new JwtTokenMissingException("No JWT token found in the request headers");
}

【讨论】:

  • 我复制了你的场景。它对我有用。您正在阅读可能包含多个(键,值)对的完整标题,我刚刚获取了令牌,即授权属性并进行了空检查。
猜你喜欢
  • 1970-01-01
  • 2016-03-25
  • 2012-08-15
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 2014-07-28
  • 1970-01-01
  • 2018-06-04
相关资源
最近更新 更多