【框架】参考 Spring Security 安全框架设计出,轻量化高可扩展的身份认证与授权架构

关键字:AOP、JWT、自定义注解、责任链模式

一、Spring Security

Spring Security 想必大家并不陌生,是 Spring 家族里的一个安全框架,特别完善,但学习成本比较大,不少开发者都觉得,这个框架"很重"

他的认证授权的过程时使用的 api 和组件比较复杂,但这不是主要的顾虑

并且,他是基于过滤器实现的,其过程抛出的异常并不会被全局异常处理器拦截,通过 SpringSecurity 认证授权的请求,才算进入我们的 Spring 环境下

但不得不说他确实有优点

  1. 对请求的一个 AOP 的统一处理(但是好像没有专门的后置处理器)
  2. 可以通过添加过滤器的方式增加认证过程,也对某些路由可添加授权过程
  3. 框架的一些注解,例如 @PreAuthorize,可以很方便的进行接口权限的设置

虽然它封装了很多现成的东西,但其实一些自己去写也没什么大不了的,还可以按照自己的想法去定制

我们可以学习它的优点去优化一下我们原本的认证授权架构

二、AOP + JWT

通过全局拦截器,拦截所有的请求,请求携带访问令牌 JWT,这里就不必多说了

三、自定义注解

自定义一个可以 Retention 为 Runtime,Target 为 TYPE 或 METHOD 的注解:

  1. 允许访问的角色
  2. 是否需要认证
  3. 是否需要授权

标注在 Controller 类才有用,若加在类上,则作用于所有方法,若标注在方法上,则以方法上的为准

意为此接口的拦截参数

java 复制代码
/**
 * Created With Intellij IDEA
 * User: 马拉圈
 * Date: 2024-08-08
 * Time: 12:50
 * <br />
 * permit: 用户必须是列表中的角色才能访问 <br />
 * authenticate: 用户需不需要通过认证 <br />
 * authorize: 用户需不需要通过授权 <br />
 * 注意: <br />
 * permit 若为 {},则代表谁都不能访问,除非 authorize 为 false <br />
 * 1. 不需要认证、不需要授权 ✅ <br />
 * 2. 需要认证、需要授权 ✅ <br />
 * 3. 需要认证、不需要授权 ✅ <br />
 * 4. 不需要认证、需要授权 ❌(必然失败) <br />
 */
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Intercept {

    UserType[] permit() default {UserType.NORMAL_USER, UserType.MANAGER};

    boolean authenticate() default true; // 默认需要认证

    boolean authorize() default true; // 默认需要授权

}
java 复制代码
@Slf4j
public class InterceptHelper {

    public static Intercept getIntercept(Class<?> clazz) {
        // 类上的 Intercept 为初步结果
        return clazz.isAnnotationPresent(Intercept.class) ? clazz.getAnnotation(Intercept.class) : null;
    }

    public static Intercept getIntercept(Method targetMethod) {
        // 获取目标方法所在的类
        Class<?> declaringClass = targetMethod.getDeclaringClass();
        // 类上的 Intercept 为初步结果
        Intercept intercept = getIntercept(declaringClass);
        // 方法上的 Intercept 为最终结果
        return targetMethod.isAnnotationPresent(Intercept.class) ? targetMethod.getAnnotation(Intercept.class) : intercept;
    }

}

四、责任链模式

责任链:

  1. 抽象处理者
  2. 具体处理者
  3. 客户端(我习惯是责任链的链头)

设计出以下架构:

  1. 前置初始化链
    1. 初始化日志变量、设置请求 id、请求 uri、请求方法,便于全链路追踪
    2. 根据配置文件对特定接口设置的拦截参数,判断当前请求的接口是否被设置了特殊的拦截参数
    3. 请求的接口如果存在目标方法,则判断其方法上或者类上是否存在 @Intercept 注解,若存在则初始化拦截参数

若不存在拦截参数,则代表该资源没有被开发者专门进行拦截的管理,直接返回错误:api 访问失败

  1. 前置认证链
    1. 是否忽略,若 authenticate 参数为 false,则直接忽略
    2. 若认证未成功且未获取 jwt,则尝试从 header 里获取 jwt
    3. 若认证未成功且未获取 jwt,则此时从 queryString 里获取 jwt
    4. 若认证未成功,则解析 jwt,若成功解析出用户信息,则存储到本地线程变量里(若令牌即将过期,则返回一个新的 jwt)

若未认证成功,则返回错误:认证失败

  1. 前置授权链
    1. 是否武略
    2. 是否强制拦截
    3. 若未授权成功,则获取当前用户的角色,判断是否存在于拦截参数的允许访问的角色列表,若存在则授权成功

若未授权成功,则返回错误:授权失败

  1. 后置链
    1. 清除日志变量、本地线程变量

在我们的架构中而一个责任链节点应该包含:

  1. 拦截的路由
  2. 执行的前置条件
  3. 执行的代码

具体代码参考:OKR-System4.0/src/main/java/cn/bitterfree/api/interceptor at main · CarefreeState/OKR-System4.0

相关推荐
程序员小假12 分钟前
线程池执行过程中遇到异常该怎么办?
java·后端
稚辉君.MCA_P8_Java16 分钟前
DeepSeek Java 单例模式详解
java·spring boot·微服务·单例模式·kubernetes
洛_尘24 分钟前
数据结构--4:栈和队列
java·数据结构·算法
疯癫的老码农30 分钟前
【小白入门docker】创建Spring Boot Hello World应用制作Docker镜像并运行
java·spring boot·分布式·docker·微服务
Mr.Entropy39 分钟前
Hibernate批量查询方法全面解析
java·后端·hibernate
绝顶少年1 小时前
Spring 框架中 RestTemplate 的使用方法
java·后端·spring
小趴菜82271 小时前
安卓人机验证View
android·java·前端
信安成长日记1 小时前
golang 写路由的时候要注意
开发语言·后端·golang
那个什么黑龙江1 小时前
关于C++中的“类中的特殊成员函数”
开发语言·c++
观望过往1 小时前
【Java SE 运算符】全面解析与实践指南
java