Skip to content

安全鉴权 · 总览

forge 的安全鉴权模块为应用提供一套开箱即用的登录认证与访问控制能力。它把「鉴权契约」与「鉴权实现」彻底分离:核心包 forge-auth 只定义接口、模型与拦截链路,具体令牌怎么签发、怎么校验,则交给可插拔的实现包完成。

在宠物商店里,这意味着:店员登录后台管理宠物(Pet)、分类(Category)、主人(Owner)等数据时走完整鉴权;而面向顾客的「在售宠物列表」「门店信息」这类接口,则可以用 @Public 注解一键放行,无须携带令牌。

模块能做什么

  • RBAC 鉴权:内置 AuthUserAuthRoleAuthUserRole 三张标准表,启动时自动播种默认管理员 admin
  • @Public 免登录:在 Controller 类或方法上一标即免登录访问,优先级高于白名单。
  • 双实现可选:forge-auth-spring-security(基于 JWT 的无状态方案)与 forge-auth-sa-token(Sa-Token 方案)二选一,由 SPI 强制唯一选中。
  • 白名单聚合:硬编码基础白名单 + 运维侧 forge.auth.white-list 配置 + 代码侧 AuthWhiteListProvider SPI 三层聚合放行。

三十秒接入

第一步,引入核心包 forge-auth(必选):

xml
<dependency>
    <groupId>cn.cvking</groupId>
    <artifactId>forge-auth</artifactId>
</dependency>

第二步,在两套实现里二选一引入。无状态 JWT 方案:

xml
<dependency>
    <groupId>cn.cvking</groupId>
    <artifactId>forge-auth-spring-security</artifactId>
</dependency>

或 Sa-Token 方案:

xml
<dependency>
    <groupId>cn.cvking</groupId>
    <artifactId>forge-auth-sa-token</artifactId>
</dependency>

两套实现不可同时存在

SPI 选择机制是 fail-fast 的:检测到 0 个或 2 个及以上鉴权实现都会启动失败。请确保 pom 里只引入了其中一个实现包。详见 鉴权实现

第三步,鉴权模块默认即启用(forge.auth.enabled=true),无须额外开关。启动应用,调用登录端点即可拿到令牌:

bash
curl -X POST http://localhost:8080/v1/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin"}'

后续请求把返回的令牌放进请求头:

bash
curl http://localhost:8080/v1/api/pet \
  -H "Authorization: Bearer <你的令牌>"

验证结果

application.yml 打开鉴权相关的 debug 日志:

yaml
logging:
  level:
    cn.cvking.forge.auth: debug

启动时控制台会打印 SPI 选中的鉴权实现,以及默认管理员的初始化结果(首次启动):

text
[auth] 使用鉴权实现: spring-security
[auth] 已创建默认管理员账号: admin
[auth] 默认管理员初始化完成,耗时 38ms

若使用了内置默认 JWT 密钥(Spring Security 方案),还会看到一条警告,提醒生产环境必须覆盖:

text
[auth] 正在使用内置默认 JWT 密钥,生产环境务必通过 forge.auth.jwt.secret 覆盖!

阅读路线

建议按下面的顺序逐篇阅读,每篇都基于宠物商店的同一套实体展开。

篇目解决的问题
快速开始完整跑通登录、携带令牌访问、注销的最小闭环
RBAC 模型AuthUserAuthRoleAuthUserRole 三表关系与默认管理员机制
@Public 与白名单免登录注解、三层白名单聚合、给顾客侧接口放行
鉴权实现Spring Security 与 Sa-Token 双实现的取舍与切换

想知道「为什么这么设计」

本系列偏重「怎么用」。如果你关心 SPI 一元性、JWT codec 下沉、为何用 ApplicationReadyEvent 落库默认管理员等设计动机,请移步设计篇 安全鉴权架构设计。涉及的 SPI 扫描、启动钩子等通用机制可参阅 前置知识

常见反例与排查

反例一:调用业务接口返回 40101,提示令牌无效

现象:携带了令牌却返回错误码 40101(TOKEN_INVALID,令牌无效或已过期,请重新登录)。

原因:常见于令牌确实过期,或请求头里令牌格式不对——默认前缀是 Bearer (注意尾部空格),缺前缀时会被当作非法令牌。

修复:确认请求头形如 Authorization: Bearer <token>;令牌过期则重新登录获取。若团队约定了不同前缀,请改 forge.auth.tokenPrefix 与客户端保持一致。

反例二:完全没带令牌访问受保护接口,返回 40100

现象:直接访问 /v1/** 接口返回错误码 40100(TOKEN_MISSING,未携带令牌,请先登录)。

原因:该接口需要登录,但请求未携带 Authorization 头,且接口未被任何白名单或 @Public 放行。

修复:先登录拿令牌再访问;若该接口本就该对外开放(如顾客侧的在售宠物列表),请用 @Public 标注或加入白名单,见 @Public 与白名单

反例三:启动报错「未检测到任何鉴权实现」或「检测到多个鉴权实现同时存在」

现象:应用启动直接失败,日志提示找不到鉴权实现,或检测到多个实现。

原因:只引了核心包 forge-auth 没引实现包,或同时引入了 forge-auth-spring-securityforge-auth-sa-token 两个实现包。

修复:检查依赖树,确保 Spring Security 与 Sa-Token 实现包恰好引入其一。这是刻意为之的 fail-fast 约束,详见 鉴权实现

反例四:登录返回 40110,确信账号没错

现象:用 admin/admin 登录返回错误码 40110(LOGIN_FAILED,用户名或密码错误)。

原因:密码以 BCrypt 存储校验,若手工改过库里的密码列、或自定义了 defaultAdminPassword 但库中老记录仍是旧密码,就会校验不通过。另外账号被禁用会返回 40111(USER_DISABLED,账号已禁用)。

修复:用配置项 forge.auth.defaultAdminUsername / forge.auth.defaultAdminPassword 对齐实际账号;默认管理员的播种是幂等的,已存在则不会覆盖密码,必要时清理旧记录后重启重新播种。