使用Spring AOP對Spring Security logout做切點的方式如下。
通常Spring專案會利用Spring AOP Aspect對Controller的請求做log(日誌)紀錄,不過Spring Security登出時預設是呼叫/logout
API並透過SecurityContextLogoutHandler
來處理登出邏輯,或透過自訂的登出處理器(logout handler)處理一些額外邏輯。若要用AOP對登出動作做log紀錄可對自訂登出處理器的方法設定Aspect切入點來達成。
範例環境如下:
- Java 1.8
- IntelliJ IDEA 2019.2.1(Community Edition)
- Spring Boot 2.2.1.RELEASE
- Maven
本範例的pom.xml
依賴設定。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
設定的自訂登出處理器DemoLogoutHandler
如下。
DemoLogoutHandler
package com.abc.demo.config.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** 自訂Spring Security 登出處理器 */
@Component
public class DemoLogoutHandler implements LogoutHandler {
@Override
public void logout(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication) {
System.out.println("DemoLogoutHandler.logout()...");
}
}
用來切向自訂登出處理器的的AOP Aspect類別DemoLogAspect
設定如下。@Pointcut
的切點為com.abc.demo.config.security.DemoLogoutHandler.logout(..)
。因此當發出請求給/logout
進行登出時,會先經過此切點並執行beforeLogout(JoinPoint joinPoint)
。
DemoLogAspect
package com.abc.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DemoLogAspect {
@Pointcut("execution(* com.abc.demo.config.security.DemoLogoutHandler.logout(..))")
public void logoutPointcut() {
}
@Before("logoutPointcut()")
public void beforeLogout(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
System.out.println(arg.getClass().getName());
}
final String username = SecurityContextHolder.getContext().getAuthentication().getName(); // 取得Spring Security登入者名稱
System.out.println("username:" + username + " logout start...");
}
}
執行登出後會在console印出以下結果。
org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest
org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterResponse
org.springframework.security.authentication.UsernamePasswordAuthenticationToken
username:user logout start...
DemoLogoutHandler.logout()...
參考:
沒有留言:
張貼留言