Spring Cloud项目如何防止重复提交,防重复提交幂等校验,Redis+aop+自定义Annotation实现接口

本文介绍了如何在Spring Cloud项目中防止重复提交,通过结合Redis、AOP和自定义Annotation实现接口幂等性。详细阐述了幂等的概念,并提供了实战演练,包括拦截器逻辑、使用示例以及项目代码,旨在解决因前端重复请求导致的数据库垃圾数据问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求说明

在项目开发过程,我们也会经常遇到这种问题,前端未拦截,或者拦截失败,导致后端接收到大量重复请求,结果把这些重复请求入库后,产生大量垃圾数据。

解释下幂等的概念:

任意多次执行所产生的影响均与一次执行的影响相同

那这个听起来是问题的解决之道,访如何实现,通常有如下方式:

  1. 建立数据库索引,保证最终插入的只有一条数据;
  2. token机制,每次接口请求前先获取一个token,然后再下次请求的时候在请求的header体中加上这个token,后台进行验证,如果验证通过删除token,下次请求再次判断token;
  3. 悲观锁或者乐观锁,悲观锁可以保证每次for update的时候其他sql无法update数据(在数据库引擎是innodb的时候,select的条件必须是唯一索引,防止锁全表)
  4. 先查询后判断,首先通过查询数据库是否存在数据,如果存在证明已经请求过了,直接拒绝该请求,如果没有存在,就证明是第一次进来,直接放行。

幂等的原理图

在这里插入图片描述

实战演练

实战中对上述进行一些优化,支持Header和判断参数值两种形式,详细看如下代码:

package vip.mate.core.ide.enums;


import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 幂等枚举类
 *
 * @author pangu
 */
@Getter
@AllArgsConstructor
public enum IdeTypeEnum {
   
   

	/**
	 * 0+1
	 */
	ALL(0, "ALL"),
	/**
	 * ruid 是针对每一次请求的
	 */
	RID(1, "RID"),
	/**
	 * key+val 是针对相同参数请求
	 */
	KEY(2, "KEY");

	private final Integer index;
	private final String title;
}

拦截器业务逻辑

package vip.mate.core.ide.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import vip.mate.core.common.aspect.BaseAspect;
import vip.mate.core.ide.annotation.Ide;
import vip.mate.core.ide.enums.IdeTypeEnum;
import vip.mate.core.ide.exception.IdeException;
import vip
<think>嗯,用户问的是在若依微服务Cloud框架中,AOP拦截器如何捕获方法上的@RequiresPermissions注解,提取权限标识如system:config:list,并检查当前用户的权限集合是否包含该标识。这些功能是在哪几个类中实现的。我需要先回忆一下若依框架的结构,尤其是权限控制相关的模块。 首先,若依微服务版是基于Spring Cloud的,权限管理应该会用到Spring Security或者Shiro。不过根据我之前的知识,若依系统通常使用Shiro进行权限控制,但在微服务版本中可能有所调整。需要确认一下。不过用户提到的是@RequiresPermissions注解,这确实是Shiro的注解,所以可能若依微服务版仍然整合了Shiro。 不过,也有可能若依微服务版转用了Spring Security,这时候权限处理可能会不同。但根据问题中的注解名称,@RequiresPermissions更可能是Shiro的,所以需要确定这一点。如果用户提到的框架使用的是Shiro,那么处理权限的拦截器应该是Shiro的AOP组件。 不过,在若依的微服务版中,可能对权限处理进行了定制,可能涉及到AOP切面来拦截注解,然后调用相关的服务来验证权限。这时候需要找到处理权限验证的切面类,以及相关的权限服务类。 根据常见的实现方式,处理注解的AOP切面类可能叫做RequiresPermissionsAspect或者类似的名称。这个类会定义切点,拦截带有@RequiresPermissions注解的方法,然后提取注解中的权限标识,接着调用权限服务来检查当前用户是否拥有该权限。 另外,权限的检查可能会涉及到获取当前用户的权限列表,这通常是在用户登录时从数据库或缓存中获取,并存储在Security上下文或者Shiro的Subject中。因此,权限服务类可能叫做PermissionService或者SysPermissionService,其中有一个方法用来检查权限是否存在。 所以,可能的类包括: 1. 处理AOP拦截的切面类,例如PreAuthorizeAspect或者RequiresPermissionsAspect,负责拦截注解并提取权限标识。 2. 权限服务类,例如SysPermissionService,负责检查用户权限集合。 3. 可能的工具类或处理用户权限的组件,例如SecurityUtils,用于获取当前用户的权限列表。 不过需要具体确认若依微服务版的代码结构。例如,在RuoYi-Cloud的代码仓库中,权限相关的处理可能在认证模块(如ruoyi-auth)或者系统模块(ruoyi-system)中,或者在通用模块里。 例如,切面类可能在ruoyi-common模块下的security包中,或者aop包中。而权限服务可能位于系统模块的service层。 假设若依使用了自定义AOP处理,那么具体的实现可能如下: - PreAuthorizeAspect类,使用@Around注解拦截带有@RequiresPermissions的方法,提取权限字符串,然后调用PermissionService进行校验。 - PermissionService中的hasPermi方法,接收权限字符串,从当前用户中获取权限列表,判断是否包含所需的权限。 - SecurityUtils类,提供获取当前用户信息的方法,如getCurrentUser(),其中包含用户的权限列表。 因此,用户的问题中的几个步骤对应的类可能是: 1. AOP拦截器:PreAuthorizeAspect(或类似名称)处理注解的拦截。 2. 提取权限标识:在切面类中通过注解对象获取value值,即权限字符串。 3. 检查权限:在PermissionService中的hasPermi或checkPermi方法实现,可能调用SecurityUtils获取用户权限。 需要验证这些类是否存在,或者是否有不同的命名习惯。例如,在若依的文档或代码中,可能有具体的类名,比如在ruoyi-common模块中的com.ruoyi.common.security.aspect.PreAuthorizeAspect,而权限服务可能在com.ruoyi.system.service.ISysPermissionService。 总结起来,用户的问题需要指出具体的类,可能需要参考若依的官方文档或源代码结构。根据常见的实现模式,给出可能的类名,并建议用户查阅相关代码以确认。</think>在若依微服务Cloud框架中,权限校验实现主要涉及以下核心类和方法,按执行流程分层解析如下: --- ### **1. 权限注解声明** **类名**:`@RequiresPermissions`(位于`com.ruoyi.common.security.annotation`包) - 该注解标记在Controller方法上,声明访问接口所需的权限标识(如`system:config:list`)。 --- ### **2. AOP拦截与权限提取** **核心类**:`PreAuthorizeAspect`(位于`com.ruoyi.common.security.aspect`包) **实现逻辑**: - **切面定义**:通过`@Around`注解拦截所有标记了`@RequiresPermissions`的方法。 - **权限提取**: ```java // 提取注解中的权限标识 RequiresPermissions requiresPermissions = joinPoint.getTarget().getClass() .getMethod(methodName, parameterTypes) .getAnnotation(RequiresPermissions.class); String permission = requiresPermissions.value()[0]; // 如 system:config:list ``` - **权限校验触发**:调用`PermissionService`进行权限检查。 --- ### **3. 权限校验逻辑** **核心类**:`SysPermissionService`(位于`com.ruoyi.system.service`包) **核心方法**:`hasPermi(String permission)` **实现逻辑**: 1. 获取当前用户的权限集合: ```java Set<String> permissions = SecurityUtils.getLoginUser().getPermissions(); ``` 2. 检查权限标识是否存在: ```java if (!permissions.contains(permission)) { throw new AccessDeniedException("无权限访问"); } ``` --- ### **4. 用户权限数据源** **数据来源**: - 用户登录时,通过`SysLoginService`(登录服务)从数据库查询用户角色和权限,并缓存到Redis。 - 权限集合通过`SecurityUtils`工具类(`com.ruoyi.common.security.utils`)动态获取。 --- ### **执行流程总结** 1. **AOP拦截** → `PreAuthorizeAspect` 捕获注解。 2. **权限提取** → 从`@RequiresPermissions`提取标识符。 3. **权限校验** → `SysPermissionService`对比用户权限集合。 4. **异常处理** → 无权限时抛出`AccessDeniedException`。 --- ### **验证建议** 若需确认具体实现细节,可查阅以下代码文件: - `PreAuthorizeAspect.java`:AOP拦截逻辑。 - `SysPermissionService.java`:权限校验核心逻辑。 - `SecurityUtils.java`:获取当前用户上下文。 此设计通过AOP解耦权限校验逻辑,确保业务代码的简洁性,同时支持动态权限管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值