【Spring】使用自定义注解方式实现AOP鉴权

AOP,是一种面向切面编程,可以通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。

在软件开发中,鉴权(Authentication)是一项非常重要的安全措施,用于验证用户身份和权限。在应用程序中,我们通常会使用AOP(Aspect-Oriented Programming)来实现鉴权功能,以便在需要进行鉴权的地方进行统一的处理。

一种常用的实现AOP鉴权的方式是使用自定义注解。通过定义一个自定义注解,并在需要进行鉴权的方法上加上该注解,我们可以在运行时通过AOP切面来拦截方法调用,并进行鉴权操作。

第一种实现逻辑

首先,我们需要定义一个自定义注解,用于标识需要进行鉴权的方法。可以使用Java的注解机制来实现,如下所示:

java 复制代码
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 Authenticated {  
    String[] roles() default {};  
}  

在上面的代码中,我们定义了一个名为Authenticated的注解,并指定了它的作用目标为方法。Authenticated注解还包含了一个可选的roles属性,用于指定允许访问该方法的用户角色。

接下来,我们需要编写一个AOP切面来实现鉴权逻辑。可以使用Spring框架提供的@Aspect注解来定义一个切面类,并使用@Around注解来实现方法拦截和鉴权逻辑,如下所示:

java 复制代码
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.ProceedingJoinPoint;  
import org.aspectj.lang.annotation.Around;  
import org.aspectj.lang.annotation.Aspect;  
import org.springframework.security.core.Authentication;  
import org.springframework.security.core.context.SecurityContextHolder;  
import org.springframework.stereotype.Component;  
  
@Aspect  
@Component  
public class AuthorizationAspect {  
  
    @Around("@annotation(authenticated)")  
    public Object authenticate(ProceedingJoinPoint joinPoint, Authenticated authenticated) throws Throwable {  
        // 获取当前用户的角色  
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();  
        String[] userRoles = authentication.getAuthorities().stream().map(Object::toString).toArray(String[]::new);  
  
        // 获取方法需要的角色  
        String[] requiredRoles = authenticated.roles();  
  
        // 鉴权逻辑  
        boolean authorized = false;  
        for (String requiredRole : requiredRoles) {  
            for (String userRole : userRoles) {  
                if (userRole.equals(requiredRole)) {  
                    authorized = true;  
                    break;  
                }  
            }  
        }  
  
        // 如果鉴权通过,则继续执行原方法,否则抛出鉴权异常  
        if (authorized) {  
            return joinPoint.proceed();  
        } else {  
            throw new AuthorizationException("Access denied");  
        }  
    }  
}  

在上面的代码中,我们定义了一个名为AuthorizationAspect的切面类,并使用@Around注解来标识需要拦截的方法。在authenticate方法中,我们首先获取当前用户的角色,然后与方法需要的角色进行比较,判断是否有权限访问该方法。

最后,我们在需要进行鉴权的方法上加上@Authenticated注解,并指定允许访问该方法的用户角色,如下所示:

java 复制代码
@Authenticated(roles = {"admin", "user"})  
public void someMethod() {  
    // 需要鉴权的方法逻辑  
} 

通过上述步骤,我们就实现了使用自定义注解方式来实现AOP鉴权。在运行时,AOP切面会拦截带有@Authenticated注解的方法调用,并进行鉴权操作。如果鉴权通过,则继续执行原方法,否则抛出鉴权异常。

第二种实现逻辑

新建一个注解类

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermissionAnnotation {
    String id() default "";
    String name() default "";
}

新建切面类

java 复制代码
@Aspect
@Component
public class PermissionAspect {

	@Pointcut("@annotation(xxx.xxx.xxx.PermissionAnnotation)")
    public void permissionPointCut() {
        // Do nothing because of it's a pointcut
    }

    @Around("permissionPointCut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        MethodSignature sign = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = sign.getMethod();
        PermissionAnnotation annotation = method.getAnnotation(PermissionAnnotation.class);
      String id= annotation.id();
      String name= annotation.name();
        if (checkPermission(id, name)) {
            // 有权限,业务方法执行
            Object result = proceedingJoinPoint.proceed();
            // 业务方法执行完可进行额外操作
            
        } else {
            // 没有权限
        }
    }
	private boolean checkPermission() {
        // 权限判断
        if (xxx) {
        return true;
        }
        return false;
    }
}

业务方法使用

java 复制代码
@Override
@PermissionAnnotation(id= "${id}")
public void deleteUser(String id) {
    //业务代码
}

其实这俩种实现逻辑基于的原理是一样的,就是看实际应用需要的是何种形式,当然也会有第三种第四种...

总结起来,使用自定义注解方式实现AOP鉴权可以提高代码的可读性和可维护性

相关推荐
喜欢读源码的小白7 分钟前
Spring Boot+MyBatis实现无限层级组织架构设计|邻接表vs闭包表性能对比|树形结构数据存储方案
java·数据库·组织结构·树级层级·无线层级
安当加密17 分钟前
基于ASP身份认证服务器实现远程办公VPN双因素认证的架构与实践
java·服务器·架构
ysdysyn31 分钟前
Java奇幻漂流:从Spring秘境到微服务星辰的冒险指南
java·spring·微服务
DARLING Zero two♡39 分钟前
【优选算法】D&C-Mergesort-Harmonies:分治-归并的算法之谐
java·数据结构·c++·算法·leetcode
天天摸鱼的java工程师1 小时前
领导:“线程池又把服务器搞崩了!” 八年 Java 开发:按业务 + 服务器配,从此稳抗大促
java·后端
初级程序员Kyle1 小时前
开始改变第四天 Java并发(2)
java·后端
SimonKing1 小时前
【开发者必备】Spring Boot 2.7.x:WebMvcConfigurer配置手册来了(六)!
java·后端·程序员
caimo2 小时前
Java无法访问网址出现Timeout但是浏览器和Postman可以
java·开发语言·postman
Deamon Tree2 小时前
ElasticSearch架构和写入、更新、删除、查询的底层逻辑
java·大数据·elasticsearch·架构
北极糊的狐2 小时前
IntelliJ IDEA插件:CodeGeeX 智能助手插件
java·ide·intellij-idea