若依AOP

项目结构:

  • ruoyi‑common:存放注解、切面
  • ruoyi‑gateway:yml 配置放行接口
  • ruoyi‑modules‑system:部门 Controller

1、自定义注解 CheckKeyId.java

路径:ruoyi‑common/src/main/java/com/ruoyi/common/annotation/CheckKeyId.java

复制代码
package com.ruoyi.common.annotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckKeyId {

}

2、AOP 切面 CheckKeyIdAspect.java

路径:ruoyi‑common/src/main/java/com/ruoyi/common/aspect/CheckKeyIdAspect.java

复制代码
package com.ruoyi.common.aspect;

import com.ruoyi.common.annotation.CheckKeyId;
import com.ruoyi.common.core.domain.AjaxResult;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class CheckKeyIdAspect {

    /**
     * 切点:拦截标记@CheckKeyId的方法
     */
    @Pointcut("@annotation(com.ruoyi.common.annotation.CheckKeyId)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return AjaxResult.error("无法获取请求上下文");
        }
        HttpServletRequest request = attributes.getRequest();

        // 获取请求头keyid
        String keyid = request.getHeader("keyid");
        final String validKey = "12345678";

        if (keyid == null || !validKey.equals(keyid.trim())) {
            return AjaxResult.error(401, "header keyid校验失败");
        }

        // 校验通过,执行controller原方法
        return joinPoint.proceed();
    }
}

3、SysDeptController 新增部门接口

路径:ruoyi‑modules‑system/src/main/java/com/ruoyi/system/controller/SysDeptController.java

复制代码
import com.ruoyi.common.annotation.CheckKeyId;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.service.ISysDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/system/dept")
public class SysDeptController {

    @Autowired
    private ISysDeptService deptService;

    /**
     * 新增部门(外部API,跳过登录,使用header keyid鉴权)
     */
    // @RequiresPermissions("system:dept:add") 注释掉权限注解
    @CheckKeyId
    @Log(title = "部门管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysDept dept)
    {
        if (!deptService.checkDeptNameUnique(dept))
        {
            return AjaxResult.error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
        }
        // 兼容未登录场景,防止SecurityUtils空指针
        String username = SecurityUtils.getUsername();
        dept.setCreateBy(username == null ? "api_external" : username);
        return AjaxResult.toAjax(deptService.insertDept(dept));
    }
}

4、网关 ruoyi‑gateway application.yml 配置【微服务必配!】

路径:ruoyi‑gateway/src/main/resources/application.yml

sa‑token 网关层放行接口,跳过 Sa‑Token 登录校验,请求才能转发到 system 服务,之后才走 AOP 校验 header

复制代码
sa-token:
  # 网关放行路径列表,不校验token
  exclude:
    - /system/dept

📝 Postman 调用示例

  • 请求方式:POST

  • URL:http://网关IP:端口/system/dept

  • 请求头:

    Content-Type: application/json
    keyid: 12345678

  • Body JSON 示例:

    {
    "deptName":"测试外部部门",
    "parentId":0,
    "sort":1,
    "status":"0"
    }

关键注意事项

  1. ruoyi‑modules‑system 必须依赖 ruoyi‑common,默认若依已经依赖无需修改 pom
  2. 鉴权顺序:网关放行 token → 请求进入 system 服务 → AOP 切面校验 header keyid → 执行业务
  3. 没有keyid或者 keyid 不等于12345678,直接返回401 header keyid校验失败,不会进入新增逻辑
  4. 生产环境务必开启 HTTPS,防止 keyid 泄露;上线不需要该接口对外开放时,恢复@RequiresPermissions、删除 yml 放行路径、移除@CheckKeyId

排错清单

  • 切面不执行:确认切面类有@Component,注解全类名写对;
  • 依旧跳登录:检查 gateway 的sa-token.exclude配置是否写对路径,改完重启 gateway 服务;
  • 空指针:确认代码中SecurityUtils.getUsername()做了 null 判断。
相关推荐
小羊没烦恼!2 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里2 天前
java中的继承和多态的区别
java
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕2 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码2 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖2 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时2 天前
01-06-A-JVM排查实战详解
java·jvm
vipxieliang2 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
ba_pi2 天前
mysql 查询所有表名并授权
java
ProcessOn官方账号2 天前
java函数式编程--入门基础
java·编程·函数式编程