优雅实现接口权限校验控制:基于自定义注解、AOP与@ConditionalOnProperty配置开关的通用解决方案

在工作项目实战开发中,用户请求API接口的时候我们会用到一个叫做权限控制的东西,我们并不希望所有用户都能访问某个接口或者网页。这个时候需要做权限控制,指定用户的角色,看这个角色是否有访问权限,然后决定其是否有访问接口网站的权限。

网上有很多这种解决方案,用于这种场景,这些方案都离不开以下技术选型:

  • 自定义注解
  • AOP

本文要解决的就是,用一个简单优雅的案例讲解这种方案,并且会在方案中加入一个控制权限功能的开关!改进这种方案!本文是我在工作项目中遇到的一种情况,这个功能开发完了,所以打算分享一下自己改进这种技术方案的做法,欢迎大家指正!

自定义注解

自定义注解的目的就是是用我们自己的注解去约束你是否有访问某个函数接口的权限,比如下面自己定义的注解 HasRole

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasRole {
    String key();
}

当我在某个函数API上面放上注解,这个函数的访问就被我们加了权限。

AOP面向切面编程

谈到AOP,我曾经写过一篇博客总结过关于AOP的知识。大家可以看我的这篇博客 《AOP面向切面编程》

我们会将一些业务放到切面类的前置通知里,当用户访问服务的时候,会先执行前置通知里的业务,这个业务其实就是一个用户身份的校验判断与提示。

比如,当我们在接口请求测试的时候会出现如下响应:

这个判断与提示其实就是在前置通知里完成的。

在AOP里,我的业务逻辑是这么写的:

java 复制代码
/**
 * @Description:
 * @return:
 * @Author: codelinghu
 * @Date: 2024/3/27
 */
@Component
@Aspect
@ConditionalOnProperty(prefix = "permission_switch", name = "enable", havingValue = "true")
public class AopConfig {

    //定义一个切点(通过注解)
    @Pointcut("@annotation(com.tongda.tdjobcard.config.annotation.HasPermission))")
    public void pointcut(){}

    private final Map<String, BaseXClient> connectMap;

    public AopConfig(Map<String, BaseXClient> connectMap) {
        this.connectMap = connectMap;
    }

    //前置通知,判断权限
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){

        //获取到HttpServletRequest,ThreadLocal
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();

        //获取用户请求的userID
        String userid = request.getHeader("userID");

        //获取当前请求的方法上的注解HasPermission中设置的角色
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
//        System.out.println("key="+signature.getName());

        BaseXClient client = connectMap.get("adminUser");
        if (client == null) {
            throw new BusinessException(ResultVoEnum.ACCOUNT_ERROR, null);
        }
        String s= PermissionDao.hasPermission(client, TdCalcConfig.DEFAULT_DBNAME,userid,signature.getName());

        //开始判断true or false
        // true放行,false拦住抛出异常
        if (!"true".equals(s)){
            throw new BusinessException(ResultVoEnum.NO_PERMISSION, null);
        }

    }

   
    }
}

其实到这里,我的功能已经实现了,接下来就是加一个配置文件的开关就行了~

@ConditionalOnProperty配置文件开关

说一下这个@ConditionalOnProperty注解哈,这个注解就是开启上面自定义注解的一个开关,在配置文件里进行开启或关闭。

如果我设置enable为false,那么我的自定义注解就会失效,下面的代码就不会被执行:

java 复制代码
@ConditionalOnProperty(prefix = "permission_switch", name = "enable", havingValue = "true")

参考文献

相关推荐
源代码•宸3 分钟前
Golang原理剖析(channel源码分析)
开发语言·后端·golang·select·channel·hchan·sudog
BlockChain8886 分钟前
MPC 钱包实战(三):Rust MPC Node + Java 调度层 + ETH 实际转账(可运行)
java·开发语言·rust
Charlie_lll6 分钟前
RAG+ReAct 智能体深度重构|从「固定三步执行」到「动态思考-行动循环」
人工智能·spring boot·redis·后端·ai·重构
Remember_9938 分钟前
【数据结构】Java集合核心:线性表、List接口、ArrayList与LinkedList深度解析
java·开发语言·数据结构·算法·leetcode·list
小旭95278 分钟前
【Java 面试高频考点】finally 与 return 执行顺序 解析
java·开发语言·jvm·面试·intellij-idea
+VX:Fegn089511 分钟前
计算机毕业设计|基于springboot + vue校园实验室管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
陌路2016 分钟前
RPC分布式通信(2)---四种典型式线程池(1)
java·开发语言·c++
微露清风16 分钟前
系统性学习C++-第二十四讲-智能指针的使用及其原理
java·c++·学习
wenjianhai24 分钟前
若依(RuoYi-Vue-Plus)框架使用WebSocket
java·若依
Coder_Boy_25 分钟前
基于SpringAI的在线考试系统-核心模块的数据模型交互关系
java·数据库·人工智能·spring boot·交互