Springboot 通过注解鉴权有两种方式:AOP方式和拦截器方式,个人建议使用拦截器方式。以下分别对这两种方式进行举例
定义注解
用于接口方法上,注解内部可以设置资源描述符来确定这个接口需要哪个权限资源
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 注解作用于方法
@Retention(RetentionPolicy.RUNTIME) // 在运行时有效
public @interface AuthRequired {
String role() default ""; // 你可以定义角色或其他参数
}
AOP 方式
在有该注解的方法上进行切面编程,判断用户是否有这个接口的权限
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import java.lang.reflect.Method;
@Aspect
@Component
public class AuthAspect {
@Before("@annotation(AuthRequired)") // 拦截有 @AuthRequired 注解的方法
public void checkAuth() throws Throwable {
// 这里可以获取当前用户的角色
String currentUserRole = getCurrentUserRole(); // 自己实现该方法获取当前用户的角色
// 获取拦截的方法
MethodSignature signature = (MethodSignature) ((org.aspectj.lang.JoinPoint) joinPoint).getSignature();
Method method = signature.getMethod();
AuthRequired authRequired = method.getAnnotation(AuthRequired.class);
String requiredRole = authRequired.role();
// 检查用户角色与方法要求的角色
if (!currentUserRole.equals(requiredRole)) {
throw new AccessDeniedException("权限不足"); // 抛出异常或返回错误响应
}
}
private String getCurrentUserRole() {
// 实现获取当前用户角色的逻辑
// 这可能涉及到 SecurityContextHolder 或其他方式
return "USER"; // 示例返回角色
}
}
使用Interceptor方式
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
AuthRequired authRequired = handlerMethod.getMethodAnnotation(AuthRequired.class);
if (authRequired != null) {
String requiredRole = authRequired.role();
String currentUserRole = getCurrentUserRole(); // 自己实现该方法获取当前用户的角色
// 检查用户角色与方法要求的角色
if (!currentUserRole.equals(requiredRole)) {
sendUnauthorizedResponse(response);
return false; // 拦截请求
}
}
}
return true; // 继续处理请求
}
private String getCurrentUserRole() {
// 实现获取当前用户角色的逻辑
// 这部分代码通常涉及到 SecurityContextHolder 或者从请求中获取用户信息
return "USER"; // 示例返回角色
}
private void sendUnauthorizedResponse(HttpServletResponse response) throws IOException {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
String jsonResponse = "{\"code\":401,\"message\":\"未登录\",\"data\":null}";
response.getWriter().write(jsonResponse);
}
}
AOP和拦截器的区别
拦截器和 AOP(面向切面编程)是不同的概念,虽然它们在某些方面有相似之处,但它们的设计目的和应用场景是不同的。
拦截器
定义:拦截器主要用于拦截特定的请求和响应,通常是处理 HTTP 请求的生命周期。它可以在请求到达 Controller 之前和响应返回之前,进行一些预处理或后处理。
应用场景:拦截器常用于权限校验、日志记录、请求参数的统一处理等。它主要关注的是处理请求的全局行为。
使用:在 Spring MVC 中,拦截器实现
HandlerInterceptor
接口,并在WebMvcConfigurer
中注册。
AOP(面向切面编程)
定义:AOP 是一种编程范式,用于将横切关注点(如日志、安全、事务管理等)从核心业务逻辑中分离出来。AOP 通过定义切面、切点和通知来实现这些功能。
应用场景:AOP 常用于日志记录、异常处理、性能监控、事务管理等,它可以在方法调用的前后执行特定的逻辑。
使用:在 Spring 中,AOP 通常通过注解(如
@Aspect
,@Before
,@After
等)实现,切面类会针对被指定的切点定义对应的通知。
对比
关注点:
拦截器主要面向 HTTP 请求的生命周期。
AOP 关注于方法的调用和相关行为,比如日志、事务等。
实现方式:
拦截器是通过实现
HandlerInterceptor
接口,关注于具体的请求和响应上下文。AOP 是通过切面(Aspect)和通知(Advice)来实现的。
适用范围:
拦截器适用于 Web 应用程序的请求处理。
AOP 适用于任何 Java 方法的横切逻辑,不限于 Web 应用。
总结
尽管拦截器和 AOP 都能实现某种程度的横切关注点处理,但它们并不是同一种概念。你可以根据业务需求选择合适的工具和设计模式来实现所需的功能。
评论区