【PmHub后端篇】PmHub中基于自定义注解和AOP的服务接口鉴权与内部认证实现
1 引言
在现代软件开发中,尤其是在微服务架构下,服务接口的鉴权和内部认证是保障系统安全的重要环节。本文将详细介绍PmHub中如何利用自定义注解和AOP(面向切面编程)实现服务接口的鉴权和内部认证,所涉及的技术知识点对于理解和实现系统安全具有重要意义。
2 注解的基本概念
在Java中,注解(Annotation)是一种特殊的语法,以@符号开头,是Java 5开始引入的新特性。注解可看作特殊的注释,用于修饰类、方法或变量,为程序在编译或运行时提供信息。例如JDK内置的@Override注解,用于帮助编译器检查方法是否正确重写父类方法。
package java.lang;import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
2.1 注解的作用
- 编译时检查:如
@Override
注解辅助编译器检查方法重写的正确性。 - 代码生成:像
@Entity
注解可告知框架生成对应的数据库表。 - 运行时处理:
@Deprecated
注解在运行时提醒开发者某方法或类已不建议使用。
2.2 注解的解析方法
- 编译期直接扫描:编译器编译Java代码时扫描注解并处理,如
@Override
注解的处理。 - 运行时通过反射处理:Spring框架中的
@Value
、@Component
等注解通过反射处理,也是自定义注解常用的解析方式。
3 自定义注解的实现
自定义注解主要包括以下几个步骤:
- 定义注解:使用
@interface
关键字定义注解。 - 注解元素:在注解中定义元素,就像在接口中定义方法。
- 元注解:使用元注解(如
@Retention
、@Target
等)来描述注解的行为。
3.1 定义注解
使用@interface关键字定义注解,例如:
import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {String value() default "";int number() default 0;
}
在上面的例子中,MyAnnotation
注解有两个元素:value
和number
。其中,number
有一个默认值0。
3.2 元注解
元注解用于描述注解本身的行为,常见元注解有:
@Retention
:指明注解的保留策略。
@Target
:指明注解的使用目标。
@Retention
:指定注解的生命周期,取值包括:RetentionPolicy.SOURCE
:注解只在源代码中存在,编译后消失。RetentionPolicy.CLASS
:注解在编译后存在于.class
文件中,运行时不存在。RetentionPolicy.RUNTIME
:注解在运行时存在,可通过反射读取。
@Target
:指定注解的使用目标,常见取值有:ElementType.TYPE
:用于类、接口、枚举、注解类型。ElementType.FIELD
:用于字段或属性。ElementType.METHOD
:用于方法。ElementType.PARAMETER
:用于参数。ElementType.CONSTRUCTOR
:用于构造函数。ElementType.LOCAL_VARIABLE
:用于局部变量。
3.3 自定义注解示例
下面是一个包含@Retention和@Target元注解的完整自定义注解示例:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {String value();int number() default 0;
}
3.4 使用自定义注解
定义完注解后,可以在代码中使用它:
public class Test {@MyAnnotation(value = "Test method", number = 42)public void testMethod() {// 方法的具体实现}
}
3.5 通过反射读取注解
import java.lang.reflect.Method;public class Main {public static void main(String[] args) throws Exception {Method method = Test.class.getMethod("testMethod");if (method.isAnnotationPresent(MyAnnotation.class)) {MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);System.out.println("Value: " + annotation.value());System.out.println("Number: " + annotation.number());}}
}
4 Spring AOP简介
AOP(面向切面编程)是一种编程范式,允许在不改变业务逻辑代码的情况下,将横切关注点(如日志记录、事务管理、安全检查等)模块化。Spring AOP提供了多种定义和使用切面的方式:
- 注解:使用
@Aspect
和相关注解(如@Before
、@After
、@Around
等)定义切面和切点。 - XML配置:在Spring配置文件中定义切面和切点,但现代开发中较少使用。
5 微服务架构下的鉴权基础
微服务架构由多个独立服务组成,服务间通讯、监控等聚合而成。其优点包括提高开发效率、增强可维护性、灵活技术选型、支持持续交付和部署、实现故障隔离、按需扩展等。
鉴权是对权限认证和授权控制,专业的鉴权框架有Spring Security和Shiro等。常见鉴权方式有:
- 用户名和密码:传统鉴权方式,需注意密码存储和传输安全。
- 多因素认证(MFA):通过多种验证因素确认用户身份,如知识因子、拥有因子、生物因子。
- OAuth(开放授权):允许第三方应用以有限权限访问用户资源,常用于社交登录和API访问控制。
- JWT(JSON Web Token):基于JSON的开放标准,用于各方之间传递声明,包含用户信息和签名,可用于鉴权和授权,PmHub采用此方式鉴权。
6 PmHub中的鉴权认证实现
6.1 PmHub架构
PmHub采用微服务架构,有单独的认证服务pmhub-auth。请求分为通过API网关的请求和微服务内部请求。
6.2 PmHub中的认证
PmHub 采用微服务架构,其认证流程如下:
- 登录请求转发
用户发起登录请求,该请求先到达网关(如端口 8080 )。网关根据配置的路由规则,将请求转发到认证中心服务pmhub - auth(如端口 6800 ) 。 - 用户信息查询
认证服务接收到登录请求后,依据用户输入的用户名,查询对应的用户信息。 - 密码校验
从Redis中获取密码相关信息(文中未明确密码存入Redis的过程,但逻辑上是从中获取用于校验 ),对用户输入的密码进行正确性校验。 - 记录登录日志
若密码校验通过,认证服务记录此次登录日志,留存登录相关信息。 - 生成登录token
认证服务生成JWT(JSON Web Token)字符串作为登录token ,JWT中包含用户信息、签名等内容。 - 存储token至Redis
将生成的JWT字符串存入Redis,并设置过期时间,以此维护用户登录状态及确定过期时间。 - 返回token信息
认证服务将生成的token信息返回给客户端。后续客户端携带该token进行请求时,系统会先去Redis检查JWT字符串是否存在,若存在则对其进行解析,能成功解析则认定用户已登录且身份合法 。
6.3 PmHub中的鉴权
6.3.1 外部请求
请求到达网关后,通过微服务的自定义请求头拦截器(放置在公共包,各服务可引用),配合自定义注解和AOP,拦截请求头获取用户和权限信息,有权限则放行,无权限则抛出异常。
6.3.2 内部请求
正常情况下内部请求无需鉴权,可以直接处理。但使用OpenFeign时,数据都是通过接口暴露出去的,为防止外部请求调用接口,采用自定义内部请求注解,AOP控制拦截,然后在内部请求调用的时候,额外加一个头字段加以区分。
PmHub做内部请求鉴权流程如下:
- 自定义注解
定义内部认证注解InnerAuth
,使用@Target(ElementType.METHOD)
指定该注解用于方法上,@Retention(RetentionPolicy.RUNTIME)
表示注解在运行时存在,可通过反射读取。注解包含元素isUser()
,用于标识是否校验用户信息,默认值为false
。代码如下:
/*** 内部认证注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InnerAuth {/*** 是否校验用户信息*/boolean isUser() default false;
}
- AOP切面控制
创建InnerAuthAspect
类,实现Ordered
接口 ,并使用@Aspect
和@Component
注解,将其定义为一个切面并纳入Spring容器管理。通过@Around("@annotation(innerAuth)")
定义环绕通知,拦截标注了InnerAuth
注解的方法。具体逻辑为:- 从请求头中获取
FROM_SOURCE
字段值,判断是否等于内部请求标识SecurityConstants.INNER
,若不相等,抛出InnerAuthException
异常,提示没有内部访问权限。 - 若配置了需校验用户信息(
innerAuth.isUser()
为true
),从请求头获取用户ID(DETAILS_USER_ID
)和用户名(DETAILS_USERNAME
),若二者有空白情况,抛出InnerAuthException
异常,提示没有设置用户信息。 - 若上述校验都通过,执行
point.proceed()
,放行请求,让目标方法正常执行。
- 从请求头中获取
代码如下:
/*** 内部服务调用验证处理*/
@Aspect
@Component
public class InnerAuthAspect implements Ordered {@Around("@annotation(innerAuth)")public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) throws Throwable {String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE);// 内部请求验证if (!StringUtils.equals(SecurityConstants.INNER, source)) {throw new InnerAuthException("没有内部访问权限,不允许访问");}String userid = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID);String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME);// 用户信息验证if (innerAuth.isUser() && (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))) {throw new InnerAuthException("没有设置用户信息,不允许访问 ");}return point.proceed();}
}
- OpenFeign请求拦截器处理
实现feign.RequestInterceptor
接口,创建FeignRequestInterceptor
类,并使用@Component
注解纳入Spring容器管理 。在apply(RequestTemplate requestTemplate)
方法中:- 获取当前请求
HttpServletRequest
。 - 从请求头中提取用户ID(
DETAILS_USER_ID
)、用户密钥(USER_KEY
)、用户名(DETAILS_USERNAME
)、认证信息(AUTHORIZATION_HEADER
)等信息,若存在则设置到RequestTemplate
的请求头中,防止用户信息在OpenFeign调用时丢失。 - 获取客户端IP,通过
X-Forwarded-For
头字段设置到请求头中。
- 获取当前请求
代码如下:
/*** feign请求拦截器*/
@Component
public class FeignRequestInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {HttpServletRequest httpServletRequest = ServletUtils.getRequest();if (StringUtils.isNotNull(httpServletRequest)) {Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);// 传递用户信息请求头,防止丢失String userId = headers.get(SecurityConstants.DETAILS_USER_ID);if (StringUtils.isNotEmpty(userId)) {requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId);}String userKey = headers.get(SecurityConstants.USER_KEY);if (StringUtils.isNotEmpty(userKey)) {requestTemplate.header(SecurityConstants.USER_KEY, userKey);}String userName = headers.get(SecurityConstants.DETAILS_USERNAME);if (StringUtils.isNotEmpty(userName)) {requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName);}String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER);if (StringUtils.isNotEmpty(authentication)) {requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication);}// 配置客户端IPrequestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr());}}
}
7 总结
本文围绕PmHub展开,介绍了Java注解的概念、实现,Spring AOP的方式。阐述微服务架构下鉴权基础,详细说明PmHub的鉴权认证流程,包括认证、外部及内部请求鉴权,旨在助力开发者理解和实现系统安全功能。
8 参考链接
- PmHub自定义注解加 AOP 实现服务接口鉴权和内部认证
- 项目仓库(GitHub)
- 项目仓库(码云):(国内访问速度更快)
相关文章:

【PmHub后端篇】PmHub中基于自定义注解和AOP的服务接口鉴权与内部认证实现
1 引言 在现代软件开发中,尤其是在微服务架构下,服务接口的鉴权和内部认证是保障系统安全的重要环节。本文将详细介绍PmHub中如何利用自定义注解和AOP(面向切面编程)实现服务接口的鉴权和内部认证,所涉及的技术知识点…...

多模态AI新纪元:Vertex AI Gemini与Spring AI深度集成实践
企业级AI集成进阶:Spring AI与Vertex AI Gemini的配置与调优实战 一、前沿技术:多模态模型的企业级配置范式 在生成式AI技术快速迭代的当下,企业级应用对模型配置的精细化需求日益增长。Vertex AI Gemini作为Google推出的多模态大模型&…...
大语言模型RLHF训练框架全景解析:OpenRLHF、verl、LLaMA-Factory与SWIFT深度对比
引言 随着大语言模型(LLM)参数规模突破千亿级,基于人类反馈的强化学习(RLHF)成为提升模型对齐能力的关键技术。OpenRLHF、verl、LLaMA-Factory和SWIFT作为开源社区的四大标杆框架,分别通过分布式架构、混合…...

开源AI数字人分身克隆小程序源码系统深度剖析:从搭建到应用
在人工智能与小程序生态深度融合的当下,开源 AI 数字人分身克隆小程序源码成为开发者的热门工具。从搭建基础环境到实现实际应用,这一过程涉及多项技术与复杂流程。本文将带您深入剖析开源 AI 数字人分身克隆小程序源码,揭开其从搭建到应用的…...

ETL背景介绍_1:数据孤岛仓库的介绍
1 ETL介绍 1.1 数据孤岛 随着企业内客户数据大量的涌现,单个数据库已不再足够。为了储存这些数据,公司通常会建立多个业务部门组织的数据库来保存数据。比如,随着数据量的增长,公司通常可能会构建数十个独立运行的业务数据库&am…...

Linux系统:虚拟文件系统与文件缓冲区(语言级内核级)
本节重点 初步理解一切皆文件理解文件缓冲区的分类用户级文件缓冲区与内核级文件缓冲区用户级文件缓冲区的刷新机制两级缓冲区的分层协作 一、虚拟文件系统 1.1 理解“一切皆文件” 我们都知道操作系统访问不同的外部设备(显示器、磁盘、键盘、鼠标、网卡&#…...

智能体的典型应用:自动驾驶、智能客服、智能制造、游戏AI与数字人技术
本文为《React Agent:从零开始构建 AI 智能体》专栏系列文章。 专栏地址:https://blog.csdn.net/suiyingy/category_12933485.html。项目地址:https://gitee.com/fgai/react-agent(含完整代码示例与实战源)。完整介绍…...
【技巧】使用UV创建python项目的开发环境
回到目录 【技巧】使用UV创建python项目的开发环境 0. 为什么用UV 下载速度快、虚拟环境、多版本python支持、清晰的依赖关系 1. 安装基础软件 1.1. 安装python 下载地址:https://www.python.org/downloads/windows/ 1.2. 安装UV > pip install uv -i ht…...
什么是时序数据库?
2025年5月13日,周二清晨 时序数据库(Time Series Database,TSDB)是一种专门用于高效存储、管理和分析时间序列数据的数据库系统。时间序列数据是指按时间顺序记录的数据点,通常包含时间戳和对应的数值或事件࿰…...
react父组件往孙子组件传值Context API
步骤: 创建一个 Context 在父组件中用 Provider 提供值 在孙子组件中用 useContext 消费值 // 创建 Context const MyContext React.createContext();// 父组件 const Parent () > {const value "Hello from parent";return (<MyContext.Provid…...
2025年第十六届蓝桥杯大赛软件赛C/C++大学B组题解
第十六届蓝桥杯大赛软件赛C/C大学B组题解 试题A: 移动距离 问题描述 小明初始在二维平面的原点,他想前往坐标(233,666)。在移动过程中,他只能采用以下两种移动方式,并且这两种移动方式可以交替、不限次数地使用: 水平向右移动…...

国联股份卫多多与七腾机器人签署战略合作协议
5月13日,七腾机器人有限公司(以下简称“七腾机器人”)市场部总经理孙永刚、销售经理吕娟一行到访国联股份卫多多,同卫多多/纸多多副总裁、产发部总经理段任飞,卫多多机器人产业链总经理郭碧波展开深入交流,…...
python学习笔记七(文件)
文章目录 Python 文件操作与异常处理全面指南一、文件基本知识1. 文件类型2. 文件操作基本步骤 二、文件操作1. 打开文件2. 读取文件内容3. 写入文件4. 关闭文件5. 使用with语句(推荐) 三、CSV文件操作1. 使用csv模块2. 读取CSV文件3. 写入CSV文件 四、异…...

WebGL 开发的前沿探索:开启 3D 网页的新时代
你是否曾好奇,为何如今网页上能呈现出如同游戏般逼真的 3D 场景?这一切都要归功于 WebGL。它看似神秘,却悄然改变着我们浏览网页的体验。以往,网页内容大多局限于二维平面,可 WebGL 打破了这一限制。它究竟凭借什么&am…...
高防服务器部署实战:从IP隐匿到协议混淆
1. IP隐匿方案设计 传统高防服务器常因源站IP暴露遭针对性攻击,群联通过三层架构实现深度隐藏: 流量入口层:域名解析至动态CNAME节点(如ai-protect.example.com)。智能调度层:AI模型分配清洗节点…...

激光雷达定位算法在FPGA中的实现——section3 Matlab实现和校验
1、校验section2的计算方法是否正确 以section1里面的图示 举个例子: 1.1 手动计算...

AI+可视化:数据呈现的未来形态
当AI生成的图表开始自动“美化”数据,当动态可视化报告能像人类一样“讲故事”,当你的眼球运动直接决定数据呈现方式——数据可视化的未来形态,正在撕裂传统认知。某车企用AI生成的3D可视化方案,让设计师集体失业;某医…...

[免费]微信小程序医院预约挂号管理系统(uni-app+SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序医院预约挂号管理系统(uni-appSpringBoot后端Vue管理端),分享下哈。 项目视频演示 【免费】微信小程序医院预约挂号管理系统(uni-appSpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩…...

【网络入侵检测】基于源码分析Suricata的IP分片重组
【作者主页】只道当时是寻常 【专栏介绍】Suricata入侵检测。专注网络、主机安全,欢迎关注与评论。 目录 目录 1.概要 2. 配置信息 2.1 名词介绍 2.2 defrag 配置 3. 代码实现 3.1 配置解析 3.1.1 defrag配置 3.1.2 主机系统策略 3.2 分片重组模块 3.2.1…...
Spring框架请求注解
Spring框架请求注解 1.RequestParam 作用:从请求的 查询参数(Query Parameters) 或 表单数据(Form Data) 中提取参数。适用场景: GET 请求的 URL 参数(如 /users?nameTom&age20ÿ…...

LVGL简易计算器实战
文章目录 📁 文件结构建议🔹 eval.h 表达式求值头文件🔹 eval.c 表达式求值实现文件(带详细注释)🔹 ui.h 界面头文件🔹 ui.c 界面实现文件🔹 main.c 主函数入口✅ 总结 项目效果&…...
【FMMT】基于模糊多模态变压器模型的个性化情感分析
遇到很难的文献看不懂,不应该感到气馁,应该激动,因为外审估计也看不太懂,那么学明白了可以吓唬他 缺陷一:输入依赖性与上下文建模不足 缺陷描述: 传统自注意力机制缺乏因果关系,难以捕捉序列历史背景多模态数据间的复杂依赖关系未被充分建模CNN/RNN类模型在…...
聊一聊接口测试依赖第三方服务变更时如何处理?
目录 一、依赖隔离与模拟 二、契约测试 三、版本控制与兼容性 四、变更监控与告警 五、容错设计 六、自动化测试维护 七、协作机制与文档自动化 第三方API突然改了参数或者返回结构,导致我们的测试用例失败,这时候该怎么办呢?首先想到…...

代码随想录算法训练营第60期第三十四天打卡
大家好,我们今天的内容依旧是贪心算法,我们上次的题目主要是围绕多维问题,那种时候我们需要分开讨论,不要一起并发进行很容易顾此失彼,那么我们今天的问题主要是重叠区间问题,又是一种全新的贪心算法思想&a…...
Midscene.js Chrome 插件实战:基于 AI 驱动 WEB UI 自动化测试「喂饭教程」
Midscene.js Chrome 插件实战:基于 AI 驱动 WEB UI 自动化测试「喂饭教程」 前言一、Midscene.js 简介二、环境准备与插件安装1. 安装 Chrome 插件2. 配置模型与 API Key三、插件界面与功能总览四、实战演练:用自然语言驱动网页自动化1. 典型场景一(Action):账号登录步骤一…...
JVM——方法内联之去虚化
引入 在Java虚拟机的即时编译体系中,方法内联是提升性能的核心手段,但面对虚方法调用(invokevirtual/invokeinterface)时,即时编译器无法直接内联,必须先进行去虚化(Devirtualizationÿ…...
Objective-C Block 底层原理深度解析
Objective-C Block 底层原理深度解析 1. Block 是什么? 1.1 Block 的本质 Block 是 Objective-C 中的特殊对象,实现了匿名函数的功能 通过 isa 指针继承自 NSObject,可以响应(如 copy、retain、release)等内存管理方…...

关于IDE的相关知识之二【插件推荐】
成长路上不孤单😊😊😊😊😊😊 【14后😊///计算机爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于ide插件推荐的相关内容!…...
Python+Streamlit实现登录页
PythonStreamlit实现登录页 Streamlit 是一个开源的 Python 库,专为数据科学家和机器学习工程师设计,用于快速构建交互式 Web 应用。 其核心功能与特点包括: 1.快速原型开发 2.交互式数据展示 3.极简开发 4.实时更新 5.内置组件 6.无前端依赖…...
RDD案例数据清洗
在 Spark 中,RDD(Resilient Distributed Dataset)是分布式数据集的基本抽象。数据清洗是数据预处理中的一个重要步骤,通常包括去除重复数据、过滤无效数据、转换数据格式等操作。以下是一个使用 RDD 进行数据清洗的完整示例。 示…...