1
我正在使用JSON Web令牌的Spring Security & Spring Security應用程序。在彈簧安全篩選器中返回自定義錯誤
我有一個彈簧安全過濾器來檢查現有JWT的存在,並且如果是這樣,注入一個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);
}
}
此過濾器被注入如下:
@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);
}
}
如果用戶傳入已過期的令牌時,會收到以下錯誤:
{
"timestamp":1496424964894,
"status":500,
"error":"Internal Server Error",
"exception":"com.app.exceptions.TokenExpiredException",
"message":"javax.servlet.ServletException: Token has expired",
"path":"/orders"
}
我知道彈簧安全性會在請求到達控制器層之前攔截請求,所以我不能使用現有的@ControllerAdvice來處理這些異常。
我的問題是,我如何定製在這裏返回的錯誤消息/對象?在其他地方,我使用JSON序列化的POJO來返回錯誤消息,我想要保持一致。我也不希望用戶看到javax.servlet.ServletException