广州10大网站服务品牌,青岛做网站建设价格低,国外社交网站建设,吉林沈阳网站建设1 引言
在现代软件开发中#xff0c;尤其是在微服务架构下#xff0c;服务接口的鉴权和内部认证是保障系统安全的重要环节。本文将详细介绍PmHub中如何利用自定义注解和AOP#xff08;面向切面编程#xff09;实现服务接口的鉴权和内部认证#xff0c;所涉及的技术知识点…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访问控制。JWTJSON Web Token基于JSON的开放标准用于各方之间传递声明包含用户信息和签名可用于鉴权和授权PmHub采用此方式鉴权。
6 PmHub中的鉴权认证实现
6.1 PmHub架构
PmHub采用微服务架构有单独的认证服务pmhub-auth。请求分为通过API网关的请求和微服务内部请求。
6.2 PmHub中的认证
PmHub 采用微服务架构其认证流程如下
登录请求转发 用户发起登录请求该请求先到达网关如端口 8080 。网关根据配置的路由规则将请求转发到认证中心服务pmhub - auth如端口 6800 。用户信息查询 认证服务接收到登录请求后依据用户输入的用户名查询对应的用户信息。密码校验 从Redis中获取密码相关信息文中未明确密码存入Redis的过程但逻辑上是从中获取用于校验 对用户输入的密码进行正确性校验。记录登录日志 若密码校验通过认证服务记录此次登录日志留存登录相关信息。生成登录token 认证服务生成JWTJSON 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 从请求头获取用户IDDETAILS_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 。从请求头中提取用户IDDETAILS_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)) {MapString, 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项目仓库码云国内访问速度更快