網頁

2020/4/10

Spring Security 自訂拒絕存取處理器 custom AccessDeniedHandler

Spring Boot Security自訂拒絕存取處理器的方式如下。

範例環境:

  • Spring Boot 2.2.1.RELEASE
  • Spring Security 5.2.1.RELEASE

請先參考Spring Boot + Spring Security 基本配置設定教學進行Spring Security的設定。


當試圖存取Spring Security保護的資源但沒有權限時,預設是由AccessDeniedHandlerImpl返回403 Forbidden錯誤。

如果要自訂拒絕存取時的處理邏輯,可新增一個類別實作AccessDeniedHandler介面並覆寫handle(...)方法,並在Spring Security配置類別中透過HttpSecurity.exceptionHandling()取得ExceptionHandlingConfigurer的實例,然後呼叫accessDeniedHandler()來設定此類別為自訂拒絕存取處理器。

例如下面是本範例的自訂拒絕存取處理器DemoAccessDeniedHandler。其實作AccessDeniedHandler並設定了@Component使其被掃描註冊為Bean。當使用者無存取權限時返回“YOU SHALL NOT PASS"訊息。

DemoAccessDeniedHandler

package com.abc.demo.config.security;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class DemoAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(
            HttpServletRequest request,
            HttpServletResponse response,
            AccessDeniedException e) throws IOException, ServletException {

        response.getOutputStream().println("YOU SHALL NOT PASS!");

    }
}

下面是範例專案的Spring Security配置類別DemoWebSecurityConfig@Autowired注入DemoAccessDeniedHandler的實例,並透過ExceptionHandlingConfigurer.accessDeniedHandler()將該實例設為拒絕存取時的處理器。

此外在DemoWebSecurityConfig類別名稱前加上@EnableGlobalMethodSecurity(securedEnabled = true)來啟用方法安全防護@Security功能。

DemoWebSecurityConfig

package com.abc.demo.config.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.AccessDeniedHandler;

@EnableGlobalMethodSecurity(securedEnabled = true) // 啟用Method Security @Security
@EnableWebSecurity
public class DemoWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    AccessDeniedHandler demoAccessDeniedHandler; // 注入自訂拒絕存取處理器的實例

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and().formLogin()
                .and().httpBasic()
                .and().exceptionHandling()
                        .accessDeniedHandler(demoAccessDeniedHandler); // 設定自訂拒絕存取處理器
    }
}


然後在DemoController.demo()方法前加上@Secured(value = "ROLE_ADMIN"),則此方法必須要有ADMIN 權限才可存取,以此來測試DemoAccessDeniedHandler的效果。

DemoController

package com.abc.demo.controller;

import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    @GetMapping(value = "/")
    @Secured(value = "ROLE_ADMIN") // <--
    public String demo() {
        return "Spring Boot + Spring Security Configuration Demo";
    }
}

最後進行測試。在本機啟動專案,在登入頁面以預設使用者登入並對http://localhost:8080/demo/發出請求。由於登入的一般使用者並無ADMIN權限,因此存取DemoController.demo()會被拒絕存取,最終透過自訂拒絕存取處理器DemoAccessDeniedHandler返回訊息。


參考:

沒有留言:

張貼留言