Spring AOP 实现为添加指定注解接口方法进行前置鉴权
需求概述
我们现在需要添加一个注解,实现 Controller 下接口方法包含此注解时,前置鉴权条件,满足条件才执行接口逻辑
思路
- 新建一个注解,如
@NeedAuthentication
- 添加一个 AspectJ 逻辑,指定 Spring AOP 切面注入方法
- 新建自定义异常,当验证不通过时抛出一个异常来终止执行
- 添加一个全局异常处理用于处理自定异常类型,返回未授权
实现
直接上代码:
NeedAuthentication.java
1 2 3 4 5 6 7 8 9 10
| package moe.muska.ami.demo.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface NeedAuthentication { }
|
AuthenticationAspect.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| package moe.muska.ami.demo.aspect;
import moe.muska.ami.demo.exception.UnauthorizedException; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect @Component public class AuthenticationAspect {
@Pointcut("@annotation(moe.muska.ami.demo.annotation.NeedAuthentication)") public void needAuthenticationMethods() {}
@Before("needAuthenticationMethods()") public void doAuth() { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); assert attributes != null; HttpServletRequest request = attributes.getRequest();
String requestUserId = request.getParameter("user_id"); String bearerToken = request.getHeader("Authorization");
if (requestUserId == null) throw new UnauthorizedException(null); if (bearerToken == null) throw new UnauthorizedException(null); long userId; try { userId = Long.parseLong(requestUserId); } catch (NumberFormatException e) { throw new UnauthorizedException("Authentication data type mismatch."); } if (!authorize(userId, bearerToken)) throw new UnauthorizedException(null); }
private boolean authorize(long userId, String bearerToken) { return true }
}
|
UnauthorizedException.java
1 2 3 4 5 6 7 8 9
| package moe.muska.ami.demo.exception;
public class UnauthorizedException extends RuntimeException { public UnauthorizedException(String message) { super(message); } }
|
AspectExceptionHandler.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package moe.muska.ami.demo.controller;
import moe.muska.ami.demo.exception.UnauthorizedException; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Map;
@RestControllerAdvice public class AspectExceptionHandler {
@ExceptionHandler(UnauthorizedException.class) public ResponseEntity<Map<String, Object>> onHttpRequestMethodNotSupportedException(UnauthorizedException ex) { return builder.unauthorized(); }
}
|
Application.java
1 2 3 4 5 6 7 8 9 10 11 12 13
| package moe.muska.ami.demo;
import org.springframework.boot.SpringApplication; import org.springframework.context.annotation.EnableAspectJAutoProxy;
@EnableAspectJAutoProxy public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
|
都写在注释里了,可以自己研究一下