gpt4 book ai didi

java - 在 spring 安全过滤器中返回自定义错误

转载 作者:行者123 更新时间:2023-12-05 03:08:56 25 4
gpt4 key购买 nike

我正在开发一个使用 JSON Web token 的 Spring Boot 和 Spring Security 应用程序。

我有一个 spring 安全过滤器,用于检查现有 JWT 是否存在,如果存在,则注入(inject)一个 UsernamePasswordAuthenticationToken:

public class AuthenticationTokenFilter extends UsernamePasswordAuthenticationFilter {

@Value("${api.token.header}")
String tokenHeader;

@Autowired
TokenUtility tokenUtility;

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;

String incomingToken = httpRequest.getHeader(tokenHeader);

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

UserDetails userDetails = null;

try {

userDetails = tokenUtility.validateToken(incomingToken);

} catch (TokenExpiredException e) {

throw new ServletException("Token has expired", e);
}

if (userDetails != null) {

UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));

SecurityContextHolder.getContext().setAuthentication(authentication);
}
}

filterChain.doFilter(servletRequest, servletResponse);
}
}

这个过滤器注入(inject)如下:

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

@Autowired
UserDetailsService userDetailsService;

@Autowired
EntryPointUnauthorizedHandler unauthorizedHandler;

@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {

authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}

@Bean
public PasswordEncoder passwordEncoder() {

return new BCryptPasswordEncoder();
}

@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {

return super.authenticationManager();
}

@Bean
public AuthenticationTokenFilter authenticationTokenFilter() throws Exception {

AuthenticationTokenFilter authenticationTokenFilter = new AuthenticationTokenFilter();
authenticationTokenFilter.setAuthenticationManager(authenticationManager());

return authenticationTokenFilter;
}

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

httpSecurity
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();

// filter injected here
httpSecurity.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}

如果用户传入已过期的 token ,他们会收到以下错误:

{
"timestamp":1496424964894,
"status":500,
"error":"Internal Server Error",
"exception":"com.app.exceptions.TokenExpiredException",
"message":"javax.servlet.ServletException: Token has expired",
"path":"/orders"
}

我知道 spring security 在请求到达 Controller 层之前拦截它们,所以我不能使用我现有的 @ControllerAdvice 来处理这些异常。

我的问题是,如何自定义此处返回的错误消息/对象?在其他地方,我使用 JSON 序列化的 POJO 来返回错误消息,并且我希望保持一致。我也不希望用户看到 javax.servlet.ServletException

最佳答案

首先,修改 JWTTokenProvider 类以使用 setAttribute() 方法将自定义 header 添加到 Http Servlet 请求。

   public boolean validateToken(String token,HttpServletRequest httpServletRequest){
try {
Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token);
return true;
}catch (SignatureException ex){
System.out.println("Invalid JWT Signature");
}catch (MalformedJwtException ex){
System.out.println("Invalid JWT token");
}catch (ExpiredJwtException ex){
System.out.println("Expired JWT token");
httpServletRequest.setAttribute("expired",ex.getMessage());
}catch (UnsupportedJwtException ex){
System.out.println("Unsupported JWT exception");
}catch (IllegalArgumentException ex){
System.out.println("Jwt claims string is empty");
}
return false;

然后修改 JwtAuthenticationEntryPoint 类中的开始方法,以检查我们上面添加的 http servlet 请求 header 中的过期 header 。

@Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {

final String expired = (String) httpServletRequest.getAttribute("expired");
System.out.println(expired);
if (expired!=null){
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,expired);
}else{
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Invalid Login details");
}

有关更多详细信息,请参阅此 Post .一个不错的简单解决方案。

关于java - 在 spring 安全过滤器中返回自定义错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44372561/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com