使用自定义注解进行权限校验

news2024/12/24 21:25:58

一,前言

对于一些重复性的操作我们可以用提取为util的方式进行处理,但也可以更简便一些,比如自定义个注解进行。选择看这篇文章的小伙伴想必都对注解不陌生,但是可能对它的工作原理不太清楚。这里我们用注解实现对接口的权限校验,让大家感受一下,自定义注解的魅力。

二, 注解的基本认识

1,作用域

我们知道,注解可以用在类上,方法上,参数上等等。这也决定了注解的作用域可以是多方面的。

主要有三类:

  • ElementType.TYPE:表示该注解可以用于类、接口(包括注解类型)或枚举声明。例如,常见的注解 @Entity@Service 就是使用在类上的注解。

  • ElementType.FIELD:表示该注解可以用于字段(包括枚举常量)。例如,常见的注解 @Autowired 就是使用在字段上的注解。

  • ElementType.METHOD:表示该注解可以用于方法声明。例如,常见的注解 @Override 就是使用在方法上的注解。

还有其它作用域。注解的作用域由 java.lang.annotation.ElementType 枚举类型定义。我们来看看有哪些吧。

public enum ElementType {
    /** Class, interface (including annotation interface), enum, or record
     * declaration */
    // 可以用于类、接口、枚举声明。
    TYPE,

    /** Field declaration (includes enum constants) */
    // 可以用于字段(包括枚举常量)。
    FIELD,

    /** Method declaration */
    // 可以用于方法声明。
    METHOD,

    /** Formal parameter declaration */
    // 可以用于参数声明。
    PARAMETER,

    /** Constructor declaration */
    // 可以用于构造函数声明。
    CONSTRUCTOR,

    /** Local variable declaration */
    // 可以用于局部变量声明。
    LOCAL_VARIABLE,

    /** Annotation interface declaration (Formerly known as an annotation type.) */
    // 可以用于注解类型声明(即声明注解的注解)。
    ANNOTATION_TYPE,

    /** Package declaration */
    // 可以用于包声明。
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    // 可以用于泛型类型参数的声明。
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    // 可以用于任何类型使用的地方,如类型转换、instanceof 表达式、new 表达式等。
    TYPE_USE,

    /**
     * Module declaration.
     *
     * @since 9
     */
    // 可以用于模块声明,即 module-info.java 文件中的 module 关键字所声明的模块。该注解用于对模块进行注解,例如指定模块的名称、版本等信息。
    MODULE,

    /**
     * Record component
     *
     * @jls 8.10.3 Record Members
     * @jls 9.7.4 Where Annotations May Appear
     *
     * @since 16
     */
    // (Record)类型,它是一种简化的数据持有类,用于替代传统的 Java Bean 类。而 RECORD_COMPONENT 注解用于标记记录类型中的组件,也就是记录的字段或者对应的 accessor 方法。
    RECORD_COMPONENT;
}

2,生命周期

注解还有一个重要的属性,就是生命周期。

注解的生命周期由 java.lang.annotation.RetentionPolicy 枚举类型定义,它规定了注解在编译时、类加载时和运行时的保留策略。

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}
  • SOURCE:该注解只在源代码中保留,编译器在编译时会丢弃这种注解,不会包含在编译后生成的 class 文件中。这意味着在运行时无法通过反射获取到这种注解。

  • CLASS:该注解在编译时会被保留到 class 文件中,但在运行时不会被虚拟机保留,因此通过反射也无法获取到。这是默认的保留策略。

  • RUNTIME:该注解在编译时会被保留到 class 文件中,并且在运行时会被虚拟机保留,因此可以通过反射机制获取到。这种注解通常用于运行时的操作,比如使用反射机制检查类的结构或者处理注解信息。

三,实践使用

1,启动类

package com.luojie;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class Applications {

    public static void main(String[] args) {
        SpringApplication.run(Applications.class, args);
    }
}

2, 注解类

package com.luojie.config.myInterface;

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})
public @interface MyPermission {
    String value() default "";
}

3,aop实现校验

这里请自己往数据库植入数据,并做好查询返回,如果有不知的地方,可以参照

Spring配置多数据库(采用数据连接池管理)_spring连接多个数据库-CSDN博客

package com.luojie.config.myInterface;

import com.luojie.common.NoPermissionException;
import com.luojie.dao.mapper1.Mapper1;
import com.luojie.moudle.UserModel;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
@Aspect
public class PermissionAspect {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private Mapper1 mapper1;

    @Before("@annotation(requiresPermission)")
    public void checkPermission(MyPermission requiresPermission) {
        String permission = requiresPermission.value();
        // 在这里进行权限校验逻辑
        // 检查用户是否拥有指定的权限,如果没有权限,可以抛出异常或者记录日志等
        if (!hasPermission(permission)) {
            throw new NoPermissionException(500, "没有权限");
        }
    }

    private boolean hasPermission(String permission) {
        // 一般我们会通过request拿token,解析token和数据库中数据比对,看用户是否有权限,这里我就简化为直接的值
        String userID = request.getHeader("userID");
        // 从数据库中拿到该用户的所有权限
        UserModel user = mapper1.getUser(userID);
        // 进行权限判断
        if (user == null) return false;
        if (user.getRoles().contains(permission)) {
            return true;
        }
        return false;
    }

}

4,统一异常处理类

package com.luojie.common;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;


@ControllerAdvice
@ResponseBody
public class CommonExceptionHandle {

    @Autowired
    private HttpServletResponse response;

    @ExceptionHandler(NoPermissionException.class)
    public ResponseCommonImpl NoPermission(NoPermissionException ex) {
        ResponseCommonImpl failedCommon = ResponseUtil.failWithNoPermission(ex.getErrorMsg());
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        return failedCommon;
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseCommonImpl handleException(Exception ex) {
        ResponseCommonImpl failedCommon = ResponseUtil.failCommon(ex.getMessage(), null);
        return failedCommon;
    }
}

5,返回类

统一返回类写法,请参照JAVA 标准接口返回与i18n国际化配置_java 后端接口返回支持国际化-CSDN博客

6,controller类

package com.luojie.controller;

import com.luojie.common.ResponseCommonImpl;
import com.luojie.common.ResponseUtil;
import com.luojie.controImpl.InterfaceTestImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class InterfaceTestController {

    @Autowired
    private InterfaceTestImpl interfaceTest;

    @GetMapping("/in/test")
    public ResponseCommonImpl test() {
        System.out.println("111111111111111222222222");
        interfaceTest.test();
        return ResponseUtil.success("ok", null);
    }
}

7,编写Impl类

package com.luojie.controImpl;

import com.luojie.common.ResponseCommonImpl;
import com.luojie.config.myInterface.MyPermission;
import org.springframework.stereotype.Service;

@Service
public class InterfaceTestImpl {

    @MyPermission("admin")
    public ResponseCommonImpl test() {
        System.out.println("ok!");
        return null;
    }
}

四,接口测试

当正确有权限的时候

当没有权限的时候的返回

如果对您有用,感谢老爷点个赞,谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1829090.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

长亭网络通信基础2

DNAT 默认路由配置方式 VRRP 买两个路由器 拥有两个虚拟网关地址 当一个路由器坏了还能进行正常上网 相当于三层闭合 提供功能 长亭笔试考题解析 三层交换机结合了路由器和交换机的特点 交换机没有路由表 不在同一网段 不能直接通信 可以给交换机VLANif 给接口配置ip地址 先…

【云岚到家】-day03-1-门户等缓存方案选择

【云岚到家】-day03-1-门户-缓存方案选择 1 门户1.1 门户简介1.2 常见的技术方案1.2.1 需求1.2.2 常见门户1.2.2.1 Web门户1.2.2.2 移动应用门户1.2.2.3 总结 2 缓存技术方案2.1 需求分析2.1.1 界面原型2.2.2 缓存需求 3 SpringCache入门3.1 基础概念3.1.1 Redis客户端3.1.2 Sp…

循环队列

循环队列是一种线性数据结构,其操作表现基于 FIFO(First In First Out,先进先出)原则并且队尾被连接在队首以形成一个循环。 这种结构克服了普通队列在元素入队和出队时需要移动大量元素的缺点。 在循环队列中,当元素…

轻松上手MYSQL:探索MySQL索引数据结构的奥秘-让数据库飞起来

​🌈 个人主页:danci_🔥 系列专栏:《设计模式》《MYSQL》💪🏻 制定明确可量化的目标,坚持默默的做事。 ✨欢迎加入探索MYSQL索引数据结构之旅✨ 👋 大家好!文本学习研…

Hadoop的读写流程

Hadoop分布式文件系统(HDFS)是Apache Hadoop项目的核心组件,它为大数据存储提供了一个可靠、可扩展的存储解决方案。本文将详细介绍HDFS的读写数据流程,包括数据的存储原理、读写过程以及优化策略。 一、HDFS简介 HDFS是一个高度容错的分布式文件系统,它设计用于运行在通…

python包管理器--- pip、conda、mamba的比较

1 pip 1.1 简介 pip是一个 Python 的包(Package)管理工具,用于从 PyPI 安装和管理 Python 标准库之外的其他包(第三方包)。从 Python 3.4 起,pip 已经成为 Python 安装程序的一部分,也是官方标准…

【chatbot-api开源项目】开发文档

chatbot-api 1. 需求分析1-1. 需求分析1-2. 系统流程图 2. 技术选型3. 项目开发3-1. 项目初始化3-2. 爬取接口获取问题接口回答问题接口创建对应对象 3-3. 调用AI3-4. 定时自动化回答 4. Docker部署5. 扩展5-1. 如果cookie失效了怎么处理5-2. 如何更好的对接多个回答系统 Gitee…

各种机器学习算法的应用场景分别是什么(比如朴素贝叶斯、决策树、K 近邻、SVM、逻辑回归最大熵模型)?

2023简直被人工智能相关话题席卷的一年。关于机器学习算法的热度,也再次飙升,网络上一些分享已经比较老了。那么今天借着查询和学习的机会,我也来浅浅分享下目前各种机器学习算法及其应用场景。 为了方便非专业的朋友阅读,我会从算…

揭秘神秘的种子:Adobe联合宾夕法尼亚大学发布文本到图像扩散模型大规模种子分析

文章链接:https://arxiv.org/pdf/2405.14828 最近对文本到图像(T2I)扩散模型的进展促进了创造性和逼真的图像合成。通过变化随机种子,可以为固定的文本提示生成各种图像。在技术上,种子控制着初始噪声,并…

FineReport简单介绍(2)

一、报表类型 模板设计是 FineReport 学习过程中的主要难题所在,FineReport 模板设计主要包括普通报表、聚合报表、决策报表三种设计类型。 报表类型简介- FineReport帮助文档 - 全面的报表使用教程和学习资料 二、聚合报表 2-1 介绍 聚合报表指一个报表中包含多个…

电商秒杀系统

一,细节 二,需要注意的细节 1.库存超卖问题 使用mysql数据库的 悲观锁 机制。在事务中使用 for update 语句,此时数据库会加锁,其他想要当前读的线程都会被阻塞,在事务处理完成之后释放这一条数据。该方法的缺点在于…

排序——希尔排序

希尔排序实际上是插入排序的优化,所以要先介绍插入排序。 目录 插入排序 思想 演示 代码实现 总结 希尔排序 思想 演示 代码 总结 插入排序 思想 又称直接插入排序。它的基本思想是将一个值插入到一个有序序列中。直至将所有的值都插入完。 演示 假设数…

工程设计问题---行星轮系设计问题

该问题的主要目标是使汽车传动比的最大误差最小。为了使最大误差最小,对自动行星传动系统的齿轮齿数进行了计算。该问题包含6个整数变量和11个不同几何约束和装配约束的约束。 参考文献: Abhishek Kumar, Guohua Wu, Mostafa Z. Ali, Rammohan Malliped…

国际统计年鉴(1995-2023年)

数据年份:1995-2023 数据格式:pdf、excel 数据内容:《国际统计年鉴》是一部综合性的国际经济社会统计资料年刊,收录了世界200多个国家和地区的统计数据,并对其中40多个主要国家和地区的经济社会发展指标及国际组织发布…

ARIMA模型与ARIMA-GARCH模型预测时间序列

上世纪 70 年代初,Ljung 等人提出 ARIMA 模型,又称求和自回归移动平均模型。其思想 是针对于非平稳时间序列进行数学建模,将其通过差分运算后 进行相关数据刻画 ,变为一个平稳的新序列,进而进行相关数据的刻画。 自 1…

Element-UI - 解决el-table中图片悬浮被遮挡问题

在开发中,发现element-ui在el-table中添加图片悬浮显示时,会被单元格遮挡的问题。通过查询得到的解决办法,大多是修改.el-table类中相关样式属性,但经过验证发现会影响到其他正常功能的使用。对于此问题解决其实也并不难&#xff…

计算机网络知识点全面总结回顾

物理层 OSI模型:数据链路层(流量控制),从传输层开始端到端;每一层的元素都称为实体,同一层的是对等实体;三个重要概念:服务(下层为上层提供调用)&#xff0c…

非连续分配管理方式(重点)

目录 一. 基本分页存储管理1.1 什么是分页存储1.2 页表 二. 基本地址变换机构三. 具有快表的地址变换机构3.1 什么是快表3.2 引入快表后, 地址的变换过程3.3 局部性原理 四. 两级页表4.1 单级页表存在什么问题?如何解决?4.2 两级页表的原理、逻辑地址结构4.3 如何实现地址变换…

机器学习笔记 - 用于3D点云数据分割的Point Net的训练

一、数据集简述 ​在本教程中,我们将学习如何在斯坦福 3D 室内场景数据集 ( S3DIS )上训练 Point Net 进行语义分割。S3DIS 是一个 3D 数据集,包含来自多栋建筑的室内空间点云,占地面积超过 6000 平方米。Point Net使用整个点云,能够执行分类和分割任务。如果你一直在关注 …

【机器学习】机器学习与教育科技在个性化教学中的融合应用与性能优化新探索

文章目录 引言机器学习与教育科技的基本概念机器学习概述监督学习无监督学习强化学习 教育科技概述学生学习行为分析个性化学习路径推荐智能化教育评估 机器学习与教育科技的融合应用实时学习数据分析数据预处理特征工程 学生成绩预测与优化模型训练模型评估 个性化学习路径推荐…