[英]How to catch AccessDeniedException in Spring Boot REST API
我有一個帶有 2 個端點的簡單 Spring Boot REST API,一個受保護,一個不受保護。 對於受保護的,我想捕獲AccessDeniedException
並發送 401 而不是默認的 500 錯誤。 這是我的安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
public void configure(WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers("/");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, org.springframework.security.access.AccessDeniedException accessDeniedException) throws IOException, ServletException {
System.out.println("I am here now!!!");
}
});
http
.addFilterAfter(getSecurityFilter(), FilterSecurityInterceptor.class);
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.csrf()
.disable();
http
.authorizeRequests()
.antMatchers("/protected").anonymous();
}
public Filter getSecurityFilter() {
return new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//do nothing here
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String appKeyHeaderValue = ((HttpServletRequest)request).getHeader("X-AppKey");
if(appKeyHeaderValue!=null && appKeyHeaderValue.equals("MY_KEY")) {
chain.doFilter(request,response);
} else {
throw new AccessDeniedException("Access denied man");
}
}
@Override
public void destroy() {
}
};
}
}
我從來沒有看到我的I am here now!!!
print 語句,我看到的是默認頁面Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Tue Jul 25 23:21:15 CDT 2017 There was an unexpected error (type=Internal Server Error, status=500). Access denied man
Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Tue Jul 25 23:21:15 CDT 2017 There was an unexpected error (type=Internal Server Error, status=500). Access denied man
Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Tue Jul 25 23:21:15 CDT 2017 There was an unexpected error (type=Internal Server Error, status=500). Access denied man
注意我的Access denied man
是如何在拋出異常時打印出來的。
當我運行項目時,我還在控制台中看到以下內容: 2017-07-25 23:21:14.818 INFO 3872 --- [ restartedMain] swsmmaRequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2017-07-25 23:21:14.818 INFO 3872 --- [ restartedMain] swsmmaRequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
這是我的項目結構的樣子:
我使用一個自定義類擴展ResponseEntityExceptionHandler
和一些注釋。
你只需要像這樣創建一個類:
@ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(AccessDeniedException.class)
public final ResponseEntity<ErrorMessage> handleAccessDeniedException(AccessDeniedException ex, WebRequest request) {
ErrorMessage errorDetails = new ErrorMessage(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.FORBIDDEN);
}
}
在這種情況下,答案將類似於:
{
"timestamp": "2018-12-28T14:25:23.213+0000",
"message": "Access is denied",
"details": "uri=/user/list"
}
正如@Afridi 所建議的那樣,異常甚至在到達控制器之前就發生了,因此必須在過濾器鏈中進行處理。 我建議執行以下操作:
public class AccessDeniedExceptionFilter extends OncePerRequestFilter {
@Override
public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
FilterChain fc) throws ServletException, IOException {
try {
fc.doFilter(request, response);
} catch (AccessDeniedException e) {
// log error if needed here then redirect
RequestDispatcher requestDispatcher =
getServletContext().getRequestDispatcher(redirecturl);
requestDispatcher.forward(request, response);
}
}
添加此過濾器以過濾鏈
protected void configure(HttpSecurity http) throws Exception {
http
....
.addFilterAfter(httpClientFilter(), AccessDeniedExceptionFilter.class)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.