说一说java中的自定义注解之设计及实现

一、需求背景

比如我们需要对系统的部分接口进行token验证,防止对外的接口裸奔。所以,在调用这类接口前,先校验token的合法性,进而得到登录用户的userId/role/authority/tenantId等信息;再进一步对比当前用户是否有权限调用该接口。

但是,不是所有的接口都需要token校验,我们应该按需配置,能够支持排除掉无需token校验的接口。

本文的重点是讲述,如果让业务方开启token校验,不会涉及到如何去做权限及接口配置等方面。

因为,接口配置,我们是建议放在api网关层(不应该放在具体的微服务里),而实际生产中,不同的业务会有不同的api网关。

二、目标

  • 接口支持token校验与否的开关控制
  • 编写一个自定义注解
  • 对业务方透明,简单易用

三、总体设计

  • 建议的方案
    在这里插入图片描述
  • 本文所说的方案
    在这里插入图片描述

四、注解的定义

  • EnableJwtAuth.java
import org.springframework.context.annotation.Import;import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableJwtAuthImportSelector.class})
public @interface EnableJwtAuth {}
  • 增加开关
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Import;import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableJwtAuthImportSelector.class})
@ConditionalOnProperty(name = "spring.jwt.enabled", havingValue = "true", matchIfMissing = true)
public @interface EnableJwtAuth {}
  • EnableJwtAuthImportSelector.java

import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;import java.util.ArrayList;
import java.util.List;
import java.util.Map;// 实现接口EnvironmentAware和ImportSelector
public final class EnableJwtAuthImportSelector implements ImportSelector, EnvironmentAware {private Environment environment;protected Environment getEnvironment() {return this.environment;}@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}// 读取配置项spring.jwt.enabled的值,默认是开启jwt校验protected boolean isEnabled() {return getEnvironment().getProperty("spring.jwt.enabled", Boolean.class, Boolean.TRUE);}@Overridepublic final String[] selectImports(AnnotationMetadata importingClassMetadata) {if (!isEnabled()) {return new String[0];}Class<EnableJwtAuth> annoType = EnableJwtAuth.class;Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(annoType.getName(), false);AnnotationAttributes attributes = AnnotationAttributes.fromMap(annotationAttributes);Assert.notNull(attributes, String.format("@%s is not present on importing class '%s' as expected",annoType.getSimpleName(), importingClassMetadata.getClassName()));// 实例化两个类List<String> classNames = new ArrayList<>(2);classNames.add(GsonAutoConfiguration.class.getName());// JwtAuthConfiguration是我们自定义的类classNames.add(JwtAuthConfiguration.class.getName());return classNames.toArray(new String[0]);}}
  • JwtAuthConfiguration.java
    此类中定义你所需要的java类。
    另外一点,如果你需要对接口uri进行过滤,也需要在这里进行校验。
    @Beanpublic JwtAuthenticationProvider jwtAuthenticationManager() {return new JwtAuthenticationProvider();}
  • JwtAuthenticationProvider.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.util.StringUtils;/*** 依赖spring security 权限框架** @author xxx*/
public class JwtAuthenticationProvider implements AuthenticationProvider {private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationProvider.class);@Overridepublic boolean supports(Class<?> authentication) {return JwtAuthenticationToken.class.isAssignableFrom(authentication);}@Overridepublic Authentication authenticate(Authentication authenticationToken)  {final String authToken = (String) authenticationToken.getCredentials();if (StringUtils.isEmpty(authToken)) {throw new AuthenticationCredentialsNotFoundException(MessageDefs.TOKEN_MISSING);}// 调用认证服务进行token校验,示意图见上面的总体设计// 下面是伪代码,自定义类JwtUser用于包装用户信息JwtUser userDetails = tokenVerifyClient.verify(authToken);// 取出需要的字段,传递给TransmittedUserInfo透传对象TransmittedUserInfo userInfo = new TransmittedUserInfo(userDetails);XxTransmittableThreadLocal<TransmittedUserInfo> xxTransmittableThreadLocal = (XxTransmittableThreadLocal<TransmittedUserInfo>) ApplicationContextProvider.getApplicationContext().getBean("xxTransmittableThreadLocal");xhTransmittableThreadLocal.set(userInfo);// 校验成功return new JwtAuthenticationToken(userDetails.getId(), null, userDetails.getAuthorities());}}

五、自定义注解的使用

在这里插入图片描述

六、说在最后的话

自定义注解,本身比较简单,这里使用了@Import注解,故不需要再在META-INF/spring.factories增加org.springframework.boot.autoconfigure.EnableAutoConfiguration配置类。

我这里想要补充说明的是,文章里的权限校验,只是一种实现方案。
更建议你在api网关中实现token的校验。

那么,java服务中,需要做哪些工作呢?

把api网关传过来的字段,很好地传承并透传至下游服务。

还有一个重要的工作就是,取出当前服务上下文中的数据,做以下工作:

  • 用户ID是否和token一致,防止token被冒用
  • 接口的权限(判断当前用户是否能够访问该接口)
  • 取出当前用户的角色、租户ID、用户ID、学校ID等关键字段,保存到数据库,并输出打印日志。

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

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

相关文章

【ESP32】Espressif-IDE及ESP-IDF安装

一、下载Espressif-IDE 2.10.0 with ESP-IDF v5.0.2 1.打开ESP-IDF 编程指南 2.点击快速入门–>安装–>手动安装–>Windows Installer–>Windows Installer Download 3.点击下载Espressif-IDE 2.10.0 with ESP-IDF v5.0.2 二、安装Espressif-IDE 2.10.0 wit…

分布式I/O,IT和OT融合少不了它

长期以来信息技术IT和操作运营技术OT是相互隔离的&#xff0c;随着大数据分析和边缘计算业务的对现场级实时数据的采集需求&#xff0c;IT和OT有了逐渐融合的趋势。IT与OT融合&#xff0c;它赋予工厂的管理者监控运行和过程的能力大为增强&#xff0c;甚至可以预测到可能发生的…

TypeScript -- 类

文章目录 TypeScript -- 类TS -- 类的概念创建一个简单的ts类继承 public / private / protected-- 公共/私有/受保护的public -- 公共private -- 私有的protected -- 受保护的 其他特性readonly -- 只读属性静态属性 -- static修饰ts的getter /setter抽象类abstract TypeScrip…

KnowStreaming系列教程第三篇——调度任务模块

前一篇文章KnowStreaming系列教程第二篇——项目整体架构分析_诸葛子房_的博客-CSDN博客 讲述了KS的整体项目目录&#xff0c;这边文章来讲述下KS在调度模块里面对于指标采集和元数据同步 一、调度模块代码主要在km-task里面 public class TaskClusterAddedListener impleme…

mybatisPlus入门篇

文章目录 初窥门径1.1 初识MybatisPlus1.2 MybatisPlus的特性1.3 MybatisPlus的架构模型 入门案例2.1 准备相关开发环境2.2 搭建springboot工程2.3 创建数据库2.4 引入相关依赖2.5 创建实体类2.6 集成MybatisPlus2.7 单元测试2.8 springboot日志优化 初窥门径 1.1 初识Mybatis…

ChatGPT把python 的import和from讲明白了

文章目录 1、import&#xff1a;import关键字用于导入整个模块&#xff0c;您可以使用该模块中的所有对象。语法如下&#xff1a;2、from ... import ...&#xff1a;from ... import ... 语法用于从模块中导入特定的对象&#xff0c;而不是导入整个模块。您可以通过这种方式选…

基于Web的智慧景区GIS三维可视化运营系统

随着人民生活水平的提高和旅游产品的丰富多样&#xff0c;我国人民对于旅游的需求逐渐从“走过场”转变为“品质体验”。 建设背景 随着互联网、大数据、人工智能等新技术在旅游领域的应用&#xff0c;以数字化、网络化、智能化为特征的智慧旅游成为旅游业高质量发展新动能。…

【雕爷学编程】Arduino动手做(93)--- 0.96寸OLED液晶屏模块11

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

Django模板语法和请求

1、在django关于模板文件加载顺序 创建的django项目下会有一个seeetings.py的文件 如果在seeetings.py 中加了 os.path.join(BASE_DIR,‘templates’)&#xff0c;如果是pycharm创建的django项目会加上&#xff0c;就会默认先去根目录找templates目录下的html文件&#xff0c…

安全学习DAY06_抓包技术-HTTPHTTPS

抓包技术-HTTP&HTTPS HTTP&HTTPS抓包针对Web&APP&小程序&PC应用等 本节目的&#xff1a; 掌握几种抓包工具证书安装操作掌握几种HTTP&HTTPS抓包工具的使用学会Web&#xff0c;APP&#xff0c;小程序&#xff0c;PC应用等抓包了解本节课抓包是针对哪些…

EAP设备自动化控制系统在设备数采和控制方面的优势

随着科技的不断进步和工业自动化的发展&#xff0c;EAP&#xff08;Equipment Automation Program&#xff09;设备自动化控制系统在各个行业中扮演着越来越重要的角色。作为连接MES&#xff08;Manufacturing Execution System&#xff09;和设备层的沟通桥梁&#xff0c;EAP系…

Chatgpt Web API 创建对话,免费,不计token数量,模仿网页提交对话

Chatgpt API 是收费的&#xff0c;按token使用量计费 Chatgpt Web API 免费的&#xff0c;只要有账号就可以使用。 curl https://chat.openai.com/backend-api/conversation \-H authority: chat.openai.com \-H accept: text/event-stream \-H accept-language: zh-CN,zh;q…

了解Unity编辑器之组件篇Mesh(三)

Mesh&#xff1a;是一种三维模型的表示形式&#xff0c;它由一系列顶点、三角形&#xff08;或其他多边形&#xff09;和相关属性组成。Mesh用于表示物体的外观和形状&#xff0c;它是可见物体的基本组成部分。通过操作Mesh&#xff0c;开发者可以实现各种视觉效果、物理模拟和…

Swagger如何将接口分组?

如果不分组管理端和用户端是混在一起的&#xff0c;不好查看。 在 docket创建的时候&#xff0c;加一行分组代码。 .groupName("用户端接口") 如果你加完之后&#xff0c;重启&#xff0c;报错。 这应该是你访问的网址仍是旧网址。 http://localhost:8080/doc.html#…

MySQL高可用之MHA集群

目录 一、MHA概述 1.1 什么是 MHA 1.2 MHA 的组成 1.3 MHA 的特点 二、MySQL MHA搭建准备 2.1 实验思路 2.2 实验准备 MHA一主两从高可用集群示意图&#xff1a; 三、搭建 MySQL MHA 3.1 配置主从复制 1、四台服务器都关闭防火墙 2、修改 Master、Slave1、Slave2 节…

汇编语言(第4版)实验7 寻址方式在结构化数据访问中的应用

参考答案&#xff1a; ①经分析&#xff0c;完整程序代码如下。 assume cs:codesg data segmentdb 1975,1976,1977,1978,1979,1980,1981,1982,1983db 1984,1985,1986,1987,1988,1989,1990,1991,1992db 1993,1994,1995dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140…

微服务笔记---Nacos集群搭建

微服务笔记---Nacos集群搭建 Nacos集群搭建1.集群结构图2.搭建集群2.1.初始化数据库2.2.下载nacos2.3.配置Nacos2.4.启动2.5.nginx反向代理2.6.优化 Nacos集群搭建 1.集群结构图 官方给出的Nacos集群图&#xff1a; 其中包含3个nacos节点&#xff0c;然后一个负载均衡器代理…

Clion开发STM32之W5500系列(DNS服务封装)

概述 在w5500基础库中进行封装&#xff0c;通过域名的方式获取实际的ip地址用于动态获取ntp的ip地址 DNS封装 头文件 /*******************************************************************************Copyright (c) [scl]。保留所有权利。****************************…

7.26作业

用fread和fwrite实现文件拷贝 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<head.h> int main(int argc, const char *argv[]) {FILE* fpfopen("./11.txt","w");FILE* fp1fopen("./12.txt",&quo…

idea的Plugins中搜索不到插件

1、ctrlalts 打开设置 ; 2、搜索框输入plugins; 3、点击plugins; 4、点齿轮按钮&#xff0c;选择HTTP Proxy settings; 如下操作&#xff1a; 5、刷新DNS&#xff0c;ipconfig /flushdns 6、重新打开idea 的plugins 插件列表出来了