網頁

2020/3/2

Spring Security AccessDeniedHandler 與 ControllerAdvice 衝突

Spring Security可以自訂AccessDeniedHandler的實作來處理拒絕存取時的邏輯,Spring Boot應用程式可能也會利用@ControllerAdvice處理各種例外。今天發現當使用@ControllerAdvice捕捉最大的例外Exception時,自訂的AccessDeniedHandler無法作用。

請先參考Spring Boot Security 自訂拒絕存取處理器的設定,然後新增標註@ControllerAdvice的類別DemoControllerAdvice如下。

DemoControllerAdvice

package com.abc.demo.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class DemoControllerAdvice {

    @ExceptionHandler({Exception.class})
    public ResponseEntity exceptionHandler() {
        return ResponseEntity.ok("Error!!");
    }

}

則當存取無權限的API時變成由DemoControllerAdvice.exceptionHandler()返回以下結果,而非透過DemoAccessDeniedHandler


原因是存取被拒時Spring Security會丟出AccessDeniedException例外,此例外屬於java.lang.Exception,而使用@ControllerAdvice處理Exception後,AccessDeniedException會先被DispatcherServlet.doDispatch()中的try catch捕捉。

若希望AccessDeniedException仍由AccessDeniedHandler處理,則可在DemoControllerAdvice中新增一個處理AccessDeniedException的方法,並再丟出新的AccessDeniedException

DemoControllerAdvice

package com.abc.demo.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class DemoControllerAdvice {

    @ExceptionHandler({AccessDeniedException.class})
    public void accessDeniedExceptionHandler(AccessDeniedException e) {
        throw new AccessDeniedException("Access denied");
    }

    @ExceptionHandler({Exception.class})
    public ResponseEntity exceptionHandler(Exception e) {
        return ResponseEntity.ok("Error!!");
    }

}

參考:

沒有留言:

張貼留言