自定义注解,通过aop来实现简单鉴权
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SpringBootAnnotation</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--aop 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
</dependencies>
</project>
自定义注解 (可以使用在方法和类上面)
package com.example.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.METHOD,//作用在方法上
ElementType.TYPE //作用在类上
})
public @interface IsAdmin {
}
切面
package com.example.aspect;
import com.example.annotation.IsAdmin;
import com.example.util.HttpUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 执行顺序
* @Around begin...
* @Before begin...
* @Before end...
* @AfterReturning begin...
* @AfterReturning end...
* @After begin...
* @After end...
* @Around end...
*/
@Component
@Aspect
public class IsAdminAspect {
private final Logger LOGGER = LoggerFactory.getLogger(IsAdminAspect.class);
@Pointcut("within(com.example.controller..*)")
private void pointCut() {}
/**
* 前置通知
*/
@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) throws IOException {
LOGGER.info("@Before begin... ");
LOGGER.info("@Before end... ");
}
/**
* 环绕通知
*/
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
LOGGER.info("@Around begin... ");
boolean needAdmin = true;
//判断类上是否有@IsAdmin注解
IsAdmin classAnnotation = joinPoint.getTarget().getClass().getAnnotation(IsAdmin.class);
if (classAnnotation == null){
//获取当前方法
MethodSignature msig = (MethodSignature) joinPoint.getSignature();
Method targetMethod = joinPoint.getTarget().getClass().getDeclaredMethod(msig.getName(), msig.getMethod().getParameterTypes());
//获取方法上的@IsAdmin注解
IsAdmin methodAnnotation = targetMethod.getAnnotation(IsAdmin.class);
// 如果类上面没有注解,则获取接口上此方法的注解
if (methodAnnotation == null) {
needAdmin = false;
}
}
Object ret = null;
if(needAdmin){
if("admin".equals(HttpUtil.getRoleFromCookie())){
ret = joinPoint.proceed();//执行到这里开始走进来的方法体(必须声明)
}else {
// 记录请求内容
HttpServletRequest request = HttpUtil.getRequest();
LOGGER.info("URL : " + request.getRequestURL().toString());
LOGGER.info("HTTP_METHOD : " + request.getMethod());
LOGGER.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
LOGGER.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
ret = "NO PERMISSION ACCESS!";
LOGGER.error((String) ret);
}
}else {
ret = joinPoint.proceed();//执行到这里开始走进来的方法体(必须声明)
}
LOGGER.info("@Around end... ");
return ret;
}
/**
* 后置通知
*/
@After("pointCut()")
public void doAfter(JoinPoint joinPoint){
LOGGER.info("@After begin... ");
LOGGER.info("@After end... ");
}
/**
* 后置通知,返回
*/
@AfterReturning(returning="ret", pointcut="pointCut()")
public void doAfterReturning(Object ret){
LOGGER.info("@AfterReturning begin... ");
LOGGER.info("@AfterReturning RET=" + ret);
LOGGER.info("@AfterReturning end... ");
}
/**
* 后置通知,抛出异常时
*/
@AfterThrowing(throwing = "e",pointcut = "pointCut()")
public void doAfterThrowing(Throwable e) {
LOGGER.info("@AfterThrowing begin... ");
LOGGER.error(e.getMessage());
LOGGER.info("@AfterThrowing end... ");
}
}
工具类
package com.example.util;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HttpUtil {
public static HttpServletRequest getRequest(){
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
return request;
}
public static HttpServletResponse getResponse(){
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletResponse response = servletRequestAttributes.getResponse();
return response;
}
public static String getRoleFromCookie() {
HttpServletRequest request = HttpUtil.getRequest();
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("role")) {
return cookie.getValue();
}
}
}
return null;
}
}
启动类
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
测试controller
package com.example.controller;
import com.example.annotation.IsAdmin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@IsAdmin
@RestController
@RequestMapping("/class1")
public class TestClassController1 {
/**
* http://127.0.0.1:8080/class1/hello
*/
@RequestMapping("/hello")
public Object hello(){
return "[CLASS1]: hello";
}
/**
* http://127.0.0.1:8080/class1/hi
*/
@RequestMapping("/hi")
public Object hi(){
return "[CLASS1]: hi";
}
}
package com.example.controller;
import com.example.annotation.IsAdmin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/class2")
public class TestClassController2 {
/**
* http://127.0.0.1:8080/class2/hello
*/
@IsAdmin
@RequestMapping("/hello")
public Object hello(){
return "[CLASS2]: hello";
}
/**
* http://127.0.0.1:8080/class2/hi
*/
@RequestMapping("/hi")
public Object hi(){
return "[CLASS2]: hi";
}
}
logback配置参见:https://blog.csdn.net/qq_17303159/article/details/111995174
切入点表达式参见:https://blog.csdn.net/qq_36951116/article/details/79172485