【PmHub后端篇】PmHub中基于自定义注解和AOP的服务接口鉴权与内部认证实现

news2025/7/18 19:48:39

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 注解的作用

  1. 编译时检查:如@Override注解辅助编译器检查方法重写的正确性。
  2. 代码生成:像@Entity注解可告知框架生成对应的数据库表。
  3. 运行时处理@Deprecated注解在运行时提醒开发者某方法或类已不建议使用。

2.2 注解的解析方法

  1. 编译期直接扫描:编译器编译Java代码时扫描注解并处理,如@Override注解的处理。
  2. 运行时通过反射处理: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注解有两个元素:valuenumber。其中,number有一个默认值0。

3.2 元注解

元注解用于描述注解本身的行为,常见元注解有:
@Retention:指明注解的保留策略。
@Target:指明注解的使用目标。

  1. @Retention:指定注解的生命周期,取值包括:
    • RetentionPolicy.SOURCE:注解只在源代码中存在,编译后消失。
    • RetentionPolicy.CLASS:注解在编译后存在于.class文件中,运行时不存在。
    • RetentionPolicy.RUNTIME:注解在运行时存在,可通过反射读取。
  2. @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提供了多种定义和使用切面的方式:

  1. 注解:使用@Aspect和相关注解(如@Before@After@Around等)定义切面和切点。
  2. XML配置:在Spring配置文件中定义切面和切点,但现代开发中较少使用。

5 微服务架构下的鉴权基础

微服务架构由多个独立服务组成,服务间通讯、监控等聚合而成。其优点包括提高开发效率、增强可维护性、灵活技术选型、支持持续交付和部署、实现故障隔离、按需扩展等。

鉴权是对权限认证和授权控制,专业的鉴权框架有Spring Security和Shiro等。常见鉴权方式有:

  1. 用户名和密码:传统鉴权方式,需注意密码存储和传输安全。
  2. 多因素认证(MFA):通过多种验证因素确认用户身份,如知识因子、拥有因子、生物因子。
  3. OAuth(开放授权):允许第三方应用以有限权限访问用户资源,常用于社交登录和API访问控制。
  4. JWT(JSON Web Token):基于JSON的开放标准,用于各方之间传递声明,包含用户信息和签名,可用于鉴权和授权,PmHub采用此方式鉴权。

6 PmHub中的鉴权认证实现

6.1 PmHub架构

PmHub采用微服务架构,有单独的认证服务pmhub-auth。请求分为通过API网关的请求和微服务内部请求
在这里插入图片描述

6.2 PmHub中的认证

PmHub 采用微服务架构,其认证流程如下:

  1. 登录请求转发
    用户发起登录请求,该请求先到达网关(如端口 8080 )。网关根据配置的路由规则,将请求转发到认证中心服务pmhub - auth(如端口 6800 ) 。
  2. 用户信息查询
    认证服务接收到登录请求后,依据用户输入的用户名,查询对应的用户信息。
  3. 密码校验
    从Redis中获取密码相关信息(文中未明确密码存入Redis的过程,但逻辑上是从中获取用于校验 ),对用户输入的密码进行正确性校验。
  4. 记录登录日志
    若密码校验通过,认证服务记录此次登录日志,留存登录相关信息。
  5. 生成登录token
    认证服务生成JWT(JSON Web Token)字符串作为登录token ,JWT中包含用户信息、签名等内容。
  6. 存储token至Redis
    将生成的JWT字符串存入Redis,并设置过期时间,以此维护用户登录状态及确定过期时间。
  7. 返回token信息
    认证服务将生成的token信息返回给客户端。后续客户端携带该token进行请求时,系统会先去Redis检查JWT字符串是否存在,若存在则对其进行解析,能成功解析则认定用户已登录且身份合法 。

在这里插入图片描述

6.3 PmHub中的鉴权

6.3.1 外部请求

请求到达网关后,通过微服务的自定义请求头拦截器(放置在公共包,各服务可引用),配合自定义注解和AOP,拦截请求头获取用户和权限信息,有权限则放行,无权限则抛出异常。
在这里插入图片描述

6.3.2 内部请求

正常情况下内部请求无需鉴权,可以直接处理。但使用OpenFeign时,数据都是通过接口暴露出去的,为防止外部请求调用接口,采用自定义内部请求注解,AOP控制拦截,然后在内部请求调用的时候,额外加一个头字段加以区分。

PmHub做内部请求鉴权流程如下:

  1. 自定义注解
    定义内部认证注解InnerAuth ,使用@Target(ElementType.METHOD)指定该注解用于方法上,@Retention(RetentionPolicy.RUNTIME)表示注解在运行时存在,可通过反射读取。注解包含元素isUser() ,用于标识是否校验用户信息,默认值为false 。代码如下:
/**
 * 内部认证注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InnerAuth {
    /**
     * 是否校验用户信息
     */
    boolean isUser() default false;
}
  1. 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();
    }
}
  1. 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 {
    @Override
    public 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);
            }
            // 配置客户端IP
            requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr());
        }
    }
}

7 总结

本文围绕PmHub展开,介绍了Java注解的概念、实现,Spring AOP的方式。阐述微服务架构下鉴权基础,详细说明PmHub的鉴权认证流程,包括认证、外部及内部请求鉴权,旨在助力开发者理解和实现系统安全功能。

8 参考链接

  1. PmHub自定义注解加 AOP 实现服务接口鉴权和内部认证
  2. 项目仓库(GitHub)
  3. 项目仓库(码云):(国内访问速度更快)

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

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

相关文章

多模态AI新纪元:Vertex AI Gemini与Spring AI深度集成实践

企业级AI集成进阶&#xff1a;Spring AI与Vertex AI Gemini的配置与调优实战 一、前沿技术&#xff1a;多模态模型的企业级配置范式 在生成式AI技术快速迭代的当下&#xff0c;企业级应用对模型配置的精细化需求日益增长。Vertex AI Gemini作为Google推出的多模态大模型&…

开源AI数字人分身克隆小程序源码系统深度剖析:从搭建到应用

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

ETL背景介绍_1:数据孤岛仓库的介绍

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

Linux系统:虚拟文件系统与文件缓冲区(语言级内核级)

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

智能体的典型应用:自动驾驶、智能客服、智能制造、游戏AI与数字人技术

本文为《React Agent&#xff1a;从零开始构建 AI 智能体》专栏系列文章。 专栏地址&#xff1a;https://blog.csdn.net/suiyingy/category_12933485.html。项目地址&#xff1a;https://gitee.com/fgai/react-agent&#xff08;含完整代码示​例与实战源&#xff09;。完整介绍…

国联股份卫多多与七腾机器人签署战略合作协议

5月13日&#xff0c;七腾机器人有限公司&#xff08;以下简称“七腾机器人”&#xff09;市场部总经理孙永刚、销售经理吕娟一行到访国联股份卫多多&#xff0c;同卫多多/纸多多副总裁、产发部总经理段任飞&#xff0c;卫多多机器人产业链总经理郭碧波展开深入交流&#xff0c;…

WebGL 开发的前沿探索:开启 3D 网页的新时代

你是否曾好奇&#xff0c;为何如今网页上能呈现出如同游戏般逼真的 3D 场景&#xff1f;这一切都要归功于 WebGL。它看似神秘&#xff0c;却悄然改变着我们浏览网页的体验。以往&#xff0c;网页内容大多局限于二维平面&#xff0c;可 WebGL 打破了这一限制。它究竟凭借什么&am…

激光雷达定位算法在FPGA中的实现——section3 Matlab实现和校验

1、校验section2的计算方法是否正确 以section1里面的图示 举个例子: 1.1 手动计算

AI+可视化:数据呈现的未来形态

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

[免费]微信小程序医院预约挂号管理系统(uni-app+SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序医院预约挂号管理系统(uni-appSpringBoot后端Vue管理端)&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序医院预约挂号管理系统(uni-appSpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩…

【网络入侵检测】基于源码分析Suricata的IP分片重组

【作者主页】只道当时是寻常 【专栏介绍】Suricata入侵检测。专注网络、主机安全&#xff0c;欢迎关注与评论。 目录 目录 1.概要 2. 配置信息 2.1 名词介绍 2.2 defrag 配置 3. 代码实现 3.1 配置解析 3.1.1 defrag配置 3.1.2 主机系统策略 3.2 分片重组模块 3.2.1…

LVGL简易计算器实战

文章目录 &#x1f4c1; 文件结构建议&#x1f539; eval.h 表达式求值头文件&#x1f539; eval.c 表达式求值实现文件&#xff08;带详细注释&#xff09;&#x1f539; ui.h 界面头文件&#x1f539; ui.c 界面实现文件&#x1f539; main.c 主函数入口✅ 总结 项目效果&…

代码随想录算法训练营第60期第三十四天打卡

大家好&#xff0c;我们今天的内容依旧是贪心算法&#xff0c;我们上次的题目主要是围绕多维问题&#xff0c;那种时候我们需要分开讨论&#xff0c;不要一起并发进行很容易顾此失彼&#xff0c;那么我们今天的问题主要是重叠区间问题&#xff0c;又是一种全新的贪心算法思想&a…

关于IDE的相关知识之二【插件推荐】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于ide插件推荐的相关内容&#xff01…

Axure RP9:列表新增

文章目录 列表新增思路新增按钮操作说明保存新增交互设置列表新增 思路 利用中继器新增行实现列表新增功能 新增按钮操作说明 工具栏中添加新增图标及标签,在图标标签基础上添加热区;对热区添加鼠标单击时交互事件,同步插入如下动作:显示/隐藏动作,设置目标元件为新增窗…

06 mysql之DML

一、什么是DML DML 用于操作数据库中的数据。主要命令包括&#xff1a; INSERT&#xff1a;添加数据SELECT&#xff1a;查询数据UPDATE&#xff1a;修改数据DELETE&#xff1a;删除数据 二、插入数据&#xff08;INSERT&#xff09; 2.1 插入单条记录 -- 插入学生记录&…

【最新版】likeshop连锁点餐系统-PHP版+uniapp前端全开源

一.系统介绍 likeshop外卖点餐系统适用于茶饮类的外卖点餐场景&#xff0c;搭建自己的一点点、奈雪、喜茶点餐系统。 系统基于总部多门店的连锁模式&#xff0c;拥有门店独立管理后台&#xff0c;支持总部定价和门店定价LBS定位点餐&#xff0c;可堂食可外卖。无论运营还是二开…

纯Java实现反向传播算法:零依赖神经网络实战

在深度学习框架泛滥的今天,理解算法底层实现变得愈发重要。反向传播(Backpropagation)作为神经网络训练的基石算法,其实现往往被各种框架封装。本文将突破常规,仅用Java标准库实现完整BP算法,帮助开发者: 1) 深入理解BP数学原理。2) 掌握面向对象的神经网络实现。3) 构建可…

海纳思(Hi3798MV300)机顶盒遇到海思摄像头

海纳思机顶盒遇到海思摄像头&#xff0c;正好家里有个海思Hi3516的摄像头模组开发板&#xff0c;结合机顶盒来做个录像。 准备工作 海纳斯机顶盒摄像机模组两根网线、两个电源、路由器一块64G固态硬盘 摄像机模组和机顶盒都接入路由器的LAN口&#xff0c;确保网络正常通信。 …

Axure应用交互设计:表格跟随菜单移动效果(超长表单)

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢!本文如有帮助请订阅 Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:表格跟随菜单移动 主要内容:表格交互设计、动态面板嵌套、拖动时事件、移动动作 应用场景…