@MFACheck 接入指南(其他微服务如何用)
任意依赖 util-server 的微服务,在方法/类上加一个 @MFACheck 注解即可获得 MFA 二次校验能力,无需写任何实现。
原理:DefaultMfaStatusProvider 已内置,一次查 auth_user_basic_t 的 totp_enabled(已绑定)与 need_totp(强制开关)两列(与 auth-server 完全一致)。
一、接入三步
1. 确认依赖(一般已有)
<dependency>
<groupId>com.xxx.cloud.spring</groupId>
<artifactId>hyper-util-server</artifactId>
<version>2.1.4-SNAPSHOT</version>
</dependency>
2. 在敏感操作上加注解
import com.xxx.util.mfa.annotation.MFACheck;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/firmware")
public class FirmwareController {
/** 固件升级:每次都要 MFA(STRICT) */
@MFACheck(action = "FW_UPGRADE", level = MFACheck.Level.STRICT)
@PostMapping("/upgrade")
public Result<Void> upgrade(@RequestBody UpgradeDto dto) {
// … 业务逻辑 …
return ResultUtil.ok();
}
/** 批量配置:5 分钟窗口内验过一次即可(LIGHT) */
@MFACheck(action = "BATCH_CONFIG", level = MFACheck.Level.LIGHT, skipWindowSeconds = 300)
@PostMapping("/batchConfig")
public Result<Void> batchConfig(@RequestBody ConfigDto dto) {
// … 业务逻辑 …
return ResultUtil.ok();
}
}
也可标在类上,对该类所有方法生效。
3. 前端处理 -9000(二次验证闭环)
被拦截时,本服务自动返回(由 util 的 MfaExceptionHandler 生成,无需自己写异常处理):
{ "code": –9000, "message": "需要 MFA 验证", "data": { "mfaChallenge": true, "action": "FW_UPGRADE" } }
前端拿到后:
Body: { "action": "FW_UPGRADE", "code": "123456" }
通过后,auth-server 会把「该用户该 action 已验证」写入共享 Redis(mfa:act:{uid}:{action})。
-9001(强制 MFA 但用户未绑定:need_totp=1 且 totp_enabled!=1)→ 前端引导用户去 auth-server /mfa/init + /mfa/enable 绑定。
判定优先级:MFA 认证 > 管理员操作密码。已绑定(totp_enabled=1)走 MFA;未绑定且 need_totp=1 引导绑定;未绑定且 need_totp=0 放行,回退既有二次密码链。
二、你自动获得了什么(零代码)
引入 util-server 后,以下组件自动装配(组件扫描 + MfaAutoConfiguration):
| MFACheckAspect | 拦截 @MFACheck,做 MFA 判定 |
| DefaultMfaStatusProvider | 默认查 auth_user_basic_t 的 totp_enabled + need_totp(@ConditionalOnMissingBean,可被覆盖) |
| MfaExceptionHandler | 把 MFA 异常转成 code=-9000/-9001 + data.action |
| MfaSessionManager | 共享 Redis 上的「窗口内已验证」状态(跨服务复用) |
| MfaProperties | mfa.* 配置绑定(多数用默认即可) |
三、前置条件(必须满足,否则默认实现会失效)
四、可选配置(application.yml,不给就用默认)
mfa:
pending:
ttlSeconds: 300 # 两步登录凭证有效期(秒)
# 其余 totp/recovery/rateLimit 项主要给 auth-server 用,消费方一般不用配
五、特殊服务:查不到 auth_user_basic_t 时覆盖默认
若某服务(独立 DB / 不连 auth 库)无法直接查该表,自定义一个 MfaStatusProvider bean,MfaAutoConfiguration 的默认实现会自动让位:
import com.xxx.util.mfa.spi.MfaStatusProvider;
import com.xxx.util.mfa.spi.MfaUserStatus;
import org.springframework.stereotype.Component;
@Component
public class RemoteMfaStatusProvider implements MfaStatusProvider {
@Override
public MfaUserStatus getStatus(String uid) {
// 例如:Feign 回调 auth-server,或查本服务用户表
// 一次返回 totp_enabled(enabled) 与 need_totp(required),避免两次查库
boolean enabled = authFeignClient.isMfaEnabled(uid);
boolean required = authFeignClient.isMfaRequired(uid);
return new MfaUserStatus(enabled, required);
}
@Override
public boolean isMfaEnabled(String uid) {
return getStatus(uid).isEnabled();
}
}
六、依赖 auth-server 提供的端点(MFA 生命周期)
消费方不需要实现这些,由 auth-server 统一提供:
| POST /mfa/init | 生成绑定二维码(首次绑定) |
| `POST /mfa/enable |




