knife4j(swagger2)实现spring security或shiro权限注解内容显示

news2024/12/28 18:51:07

在前后端交互时,某些接口需要指定权限才能访问,虽然可以在@ApiOperation注解的notes参数上自己加上,但是每个接口都要手动写,有点儿。。。

基于此需求,我们可以使用swagger提供的OperationBuilderPlugin,通过扫描权限注解自动扩展接口的描述信息

项目使用到哪个权限框架,就用哪个配置就行,能直接使用

文档参数分组可参考之前的组件封装:swagger2文档基于knife4j 2.0.5二次封装工具
组件提供了诸如yaml配置分组等一些功能,可自行查看更新日志使用

1 Spring Security 注解展示

将Spring Security的PostAuthorizePostFilterPreAuthorizePreFilter的注解信息追加到接口描述中.

import com.google.common.base.Optional;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.swagger.common.SwaggerPluginSupport;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;

@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1001)
public class SecurityOperationBuilderPlugin implements OperationBuilderPlugin {

    @Override
    public void apply(OperationContext context) {
        String notes = context.operationBuilder().build().getNotes();
        StringBuilder notesBuilder = new StringBuilder(notes == null ? "" : notes);
        getClassAnnotationNote(notesBuilder, context);
        getMethodAnnotationNote(notesBuilder, context);
        context.operationBuilder().notes(notesBuilder.toString());
    }

    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }

    private void getClassAnnotationNote(StringBuilder notesBuffer, OperationContext context) {
        List<String> values = getAnnotationValues(context, OperationContext::findControllerAnnotation);
        if (!values.isEmpty()) {
            notesBuffer.append("<p />").append("class: ").append(String.join(",", values));
        }
    }

    private void getMethodAnnotationNote(StringBuilder notesBuffer, OperationContext context) {
        List<String> values = getAnnotationValues(context, OperationContext::findAnnotation);
        if (!values.isEmpty()) {
            notesBuffer.append("<p />").append("method: ").append(String.join(",", values));
        }
    }

    private <T, R> List<String> getAnnotationValues(T target, BiFunction<T, Class<? extends Annotation>, Optional<R>> findAnnotation) {
        List<String> values = new ArrayList<>();
        Optional<R> postAuthorize = findAnnotation.apply(target, PostAuthorize.class);
        if (postAuthorize.isPresent()) {
            values.add(((PostAuthorize) postAuthorize.get()).value());
        }
        Optional<R> postFilter = findAnnotation.apply(target, PostFilter.class);
        if (postFilter.isPresent()) {
            values.add(((PostFilter) postFilter.get()).value());
        }
        Optional<R> preAuthorize = findAnnotation.apply(target, PreAuthorize.class);
        if (preAuthorize.isPresent()) {
            values.add(((PreAuthorize) preAuthorize.get()).value());
        }
        Optional<R> preFilter = findAnnotation.apply(target, PreFilter.class);
        if (preFilter.isPresent()) {
            values.add(((PreFilter) preFilter.get()).value());
        }
        return values;
    }
}

2 Apache Shiro 注解展示

将Apache Shiro的RequiresRolesRequiresPermissions的注解信息追加到接口描述中.

import com.google.common.base.Optional;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.swagger.common.SwaggerPluginSupport;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;

@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1001)
public class ShiroOperationBuilderPlugin implements OperationBuilderPlugin {

    private static final String HTML_P = "<p />";
    private static final String PERM = "权限:";
    private static final String ROLE = "角色:";

    @Override
    public void apply(OperationContext context) {
        String notes = context.operationBuilder().build().getNotes();
        StringBuilder notesBuilder = new StringBuilder(notes == null ? "" : notes);
        getClassAnnotationNote(notesBuilder, context);
        getMethodAnnotationNote(notesBuilder, context);
        context.operationBuilder().notes(notesBuilder.toString());
    }

    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }

    private void getClassAnnotationNote(StringBuilder notesBuffer, OperationContext context) {
        List<String> values = getAnnotationValues(context, OperationContext::findControllerAnnotation);
        if (!values.isEmpty()) {
            notesBuffer.append(HTML_P).append("class: ").append(HTML_P).append(String.join("", values));
        }
    }

    private void getMethodAnnotationNote(StringBuilder notesBuffer, OperationContext context) {
        List<String> values = getAnnotationValues(context, OperationContext::findAnnotation);
        if (!values.isEmpty()) {
            notesBuffer.append(HTML_P).append("method: ").append(HTML_P).append(String.join("", values));
        }
    }

    private <T, R> List<String> getAnnotationValues(T target, BiFunction<T, Class<? extends Annotation>, Optional<R>> findAnnotation) {
        List<String> values = new ArrayList<>();
        Optional<R> permissions = findAnnotation.apply(target, RequiresPermissions.class);
        if (permissions.isPresent()) {
            RequiresPermissions requiresPermissions = (RequiresPermissions) permissions.get();
            values.add(HTML_P + PERM + getAnnotationNote(requiresPermissions.value(), requiresPermissions.logical()));
        }
        Optional<R> roles = findAnnotation.apply(target, RequiresRoles.class);
        if (roles.isPresent()) {
            RequiresRoles requiresRoles = (RequiresRoles) roles.get();
            values.add(HTML_P + ROLE + getAnnotationNote(requiresRoles.value(), requiresRoles.logical()));
        }
        return values;
    }

    private String getAnnotationNote(String[] values, Logical logical) {
        if (logical.equals(Logical.AND)) {
            return String.join(" && ", values);
        } else {
            return String.join(" || ", values);
        }
    }
}

3 Controller演示

3.1 spring security

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/swagger")
@Api(tags = "security 注解权限展示")
@PostAuthorize("hasAuthority('class')")
@PostFilter("hasAuthority('class')")
@PreAuthorize("hasAuthority('class')")
@PreFilter("hasAuthority('class')")
public class SecuritySwaggerController {

    @GetMapping("/security")
    @ApiOperation(value = "security", notes = "Spring Security注解追加到接口描述")
    @PostAuthorize("hasAuthority('method')")
    @PostFilter("hasAuthority('method')")
    @PreAuthorize("hasAuthority('method')")
    @PreFilter("hasAuthority('method')")
    public String security() {
        return "hello security";
    }
}

3.2 apache shiro

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/swagger")
@Api(tags = "shiro 注解权限展示")
@RequiresRoles(value = {"class:role1","class:role2"})
@RequiresPermissions(value = {"class:prem1","class:perm2"}, logical = Logical.OR)
public class ShiroSwaggerController {

    @GetMapping("/shiro")
    @ApiOperation(value = "shiro", notes = "Apache Shiro注解追加到接口描述")
    @RequiresRoles(value = {"method:role1","method:role2"})
    @RequiresPermissions(value = {"method:prem1","method:perm2"}, logical = Logical.OR)
    public String shiro() {
        return "hello shiro";
    }
}

4 效果展示

在这里插入图片描述
在这里插入图片描述
参考:https://blog.csdn.net/qq_34347620/article/details/128470082,在此基础上做了一些改进。

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

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

相关文章

档案库房空气质量温湿度一体化平台解决方案

档案馆温湿度十防环境一体化解决平台方案 说明&#xff1a;档案库房温湿度一般要达到如下要求&#xff1a; 在选定温度、湿度后&#xff0c;每昼夜波动幅度温度≦2℃&#xff0c;湿度≦5%RH。 下表是档案库房温湿度要求列表&#xff1a; 档案库房温湿度要求 项 目 温湿度范…

企业给员工内部搭建知识库用什么好?

企业给员工内部搭建知识库是一种有效的知识管理方式&#xff0c;可以帮助企业更好地管理和共享知识资源&#xff0c;提高员工的工作效率和学习能力。本文将介绍企业搭建内部知识库的好处、搭建方法和注意事项等方面的内容&#xff0c;希望对企业进行知识管理的决策者有所帮助。…

青年就业创业数据分析:视频相关就业已成为数字生态就业的主要发展形式

哈喽大家好&#xff0c;随着网络的普及&#xff0c;利用数字科技与互联网技术&#xff0c;以青年群体为主要对象&#xff0c;数字生态行业催生出了一大批新兴的就业岗位。世界范围内&#xff0c;数字生态经济已成为不少国家经济发展的重要支撑&#xff0c;成为解决青年就业问题…

00后腾讯T3-2 晒出工资单:狠补了这个,真香…

最近一哥们跟我聊天装逼&#xff0c;说他最近从腾讯跳槽了&#xff0c;我问他跳出来拿了多少&#xff1f;哥们表示很得意&#xff0c;说跳槽到新公司一个月后发了工资&#xff0c;月入5万多&#xff0c;表示很满足&#xff01;这样的高薪资着实让人羡慕&#xff0c;我猜这是税后…

采用Prometheus+Grafana+Altermanager搭建部署K8S集群节点可视化监控告警平台

文章目录 1. 实验节点规划表2. 安装Prometheus3. 安装node_exporter4. 配置prometheus.yml文件5. 安装Grafana6. 安装Altermanager监控告警 采用 "PrometheusGrafana"的开源监控系统&#xff0c;安装部署K8S集群监控平台。 并使用Altermanager告警插件&#xff0c;配…

AutoSAR系列讲解(入门篇)1.2-AutoSAR的概述

目录 一、到底什么是AutoSAR 1、大白话来讲 2、架构上来讲 应用软件层(APPL) 实时运行环境&#xff08;RTE&#xff09; 基础软件层(BSW) 3、工具链上来讲 二、AutoSAR的目标 一、到底什么是AutoSAR 1、大白话来讲 AUTOSAR 就是AUTomotive Open System ARchitecture的…

nginx页面优化及yum安装LNMP

文章目录 一.nginx优化1.版本号1.1查看版本号1.2修改版本号1.2.1修改配置文件1.2.2修改源码文件&#xff0c;重新编译安装 2.nginx的日志分割2.1 写日志分割的脚本2.2给脚本执行权限、执行2.3创建定时任务可以每个月固定分割一次 3.nginx的页面压缩3.1配置3.2验证 4.图片缓存4.…

FPGA通信—千兆网(RTL8211EG)硬件设计

一、硬件布局指南 创造一个低噪音、功率稳定的环境降低EMI/EMC的程度及其对RTL8211E/RTL8211EG的影响简化信号跟踪的路由任务 1.1 布局 RTL8211EG 必须尽可能靠近MAC&#xff08;小于2.5英寸6.35cm&#xff09;连接到RSET引脚的电阻器应靠近RTL8211E/RTL8211EG&#xff08…

jmeter接口测试教程以及接口测试流程详解

目录 前言&#xff1a; 一、Jmeter简介 二、Jmeter安装 三、设置Jmeter语言为中文环境 四、Jmeter主要元件 五、Jmeter元件的作用域和执行顺序 六、Jmeter进行接口测试流程 七、Jmeter进行接口测试流程步骤详解 前言&#xff1a; JMeter是一款功能强大的性能测试工具&…

【算法与数据结构】18、LeetCode四数之和

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题的解法借助了【算法与数据结构】15、LeetCode三数之和的算法思想。首先我们进行排序&#xff0c;然…

用实例阐述回溯算法

目录 什么是回溯算法&#xff1f; 基本概念 示例认知 什么时候可以使用回溯算法&#xff1f; 回溯算法经典应用-无向图两节点之间路径 问题描述 回溯过程 代码示例 回溯算法经典应用-四皇后问题 问题描述 四皇后问题解决步骤 Step 1 Step 2 Step 3 Step 4 Step…

ICC2:polygon多边形操作

有时候想画一个环形或者不规则形状的metal shape/blockage,一遇到更新floorplan都要重新画,手工活如果能被脚本替代肯定是最优解,ICC2就提供这样的一组命令有效提高工作效率。 1.创建polygon 先看一下创建polygon的操作: create_poly_rect:提供一组或多组boundary坐标,工…

OpenCL编程指南-5.2数学函数

数学函数 OpenCL C实现了C99规范中描述的数学函数。使用这些数学函数的应用程序需要在代码中包含math.h头文件。这些数学函数可以作为OpenCL内核的内置函数。 对于表5-2和表5-3中的数学函数&#xff0c;我们将使用泛型类型名gentype指示这些函数可以取float、float2、float3、…

【AUTOSAR】CCP协议的代码分析与解读(二)----CCP协议格式和命令代码

CCP协议介绍 CCP的全称是CAN Calibration Protocol (CAN标定协议)&#xff0c;是基于CAN总线的ECU标定协议规范。CCP协议遵从CAN2.0通信规范&#xff0c;支持11位标准与29位扩展标识符。 CCP通信方式 CCP协议采用主从通信方式&#xff0c;如上图所示&#xff0c;其中从设备是…

Visual modflow Flex地下水数值模拟教程

详情点击链接&#xff1a;Visual modflow Flex地下水数值模拟及参数优化、抽水实验设计与处理、复杂的饱和/非饱和地下水流分析 一&#xff0c;地下水数值软件的操作流程、建模步骤和所需资料处理 [1] Visual MODFLOW Flex特征[2] Visual MODFLOW Flex软件界面及模块 [3] 地…

详细讲解接口自动化攻略

目录 前言&#xff1a; 为什么要做接口自动化 问题在哪里 全靠参数化 接口间参数传递 测试数据参数化 测试断言 测试管理 导入测试用例 接口执行顺序 使用测试数据集 测试参数配置 运行结果&测试报告 测试套件 前言&#xff1a; 接口自动化是提高测试效率和…

ThreadX在gcc下的移植

本文介绍ThreadX在arm-none-eabi-gcc编译器下的移植方法。 1、ThreadX介绍和源码获取 threadx的介绍和源码获取请参考之前的博文&#xff1a;ThreadX在mdk(AC5)中的移植。 2、准备工作 本篇主要介绍threadx在corex-m7上的移植&#xff0c;编译器使用arm-none-eabi-gcc。 在…

智能井盖传感器:以科技破解城市顽疾

在城市的道路网络中&#xff0c;井盖扮演着重要的角色&#xff0c;用于覆盖下方的管道和设施&#xff0c;然而&#xff0c;由于井盖的老化、损坏或被盗&#xff0c;常常会导致安全问题的发生&#xff0c;如路面塌陷、行人受伤等。井盖的状态监测和维护一直是城市管理者面临的挑…

2023年8月PMP考试,考生需要关注这些!

经PMI和中国国际人才交流基金会研究决定&#xff0c;中国大陆地区2023年第三期PMP认证考试定于8月19日举办。考生须认真阅读下文&#xff0c;知悉考试安排及注意事项&#xff0c;并遵守考试有关规定。 考生须认真阅读下文&#xff0c;知悉考试安排及注意事项&#xff0c;并遵守…