【双因子认证】拦截注解@MFACheck 接入指南(其他微服务如何用)

@MFACheck 接入指南(其他微服务如何用)

任意依赖 hyper-util-server 的微服务,在方法/类上加一个 @MFACheck 注解 即可获得 MFA 二次校验能力,无需写任何实现

原理:DefaultMfaStatusProvider 已内置,一次查 auth_user_basic_ttotp_enabled(已绑定)与 need_totp(强制开关)两列(与 auth-server 完全一致)。

一、接入三步

1. 确认依赖(一般已有)

xml 复制代码
<dependency>
    <groupId>com.xxx.cloud.spring</groupId>
    <artifactId>hyper-util-server</artifactId>
    <version>2.1.4-SNAPSHOT</version>
</dependency>

2. 在敏感操作上加注解

java 复制代码
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 生成,无需自己写异常处理):

json 复制代码
{ "code": -9000, "message": "需要 MFA 验证", "data": { "mfaChallenge": true, "action": "FW_UPGRADE" } }

前端拿到后:

  1. 弹窗让用户输入 Authenticator 动态码;

  2. auth-server 的统一二次校验接口(不是本服务):

    复制代码
    POST {auth-server}/mfa/verifyAction
    Body: { "action": "FW_UPGRADE", "code": "123456" }

    通过后,auth-server 会把「该用户该 action 已验证」写入共享 Redismfa:act:{uid}:{action})。

  3. 重放原请求 (再调一次本服务的 /firmware/upgrade)→ 切面读到共享 Redis 里已验证 → 放行。

-9001(强制 MFA 但用户未绑定:need_totp=1totp_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_ttotp_enabled + need_totp@ConditionalOnMissingBean,可被覆盖)
MfaExceptionHandler 把 MFA 异常转成 code=-9000/-9001 + data.action
MfaSessionManager 共享 Redis 上的「窗口内已验证」状态(跨服务复用)
MfaProperties mfa.* 配置绑定(多数用默认即可)

三、前置条件(必须满足,否则默认实现会失效)

  1. 默认数据源能读到 auth_user_basic_t(和 auth-server 一样查这张表)。

  2. @MapperScan 覆盖 com.xxx.util.*.mapper (否则 AuthUserMfaMapper 注入不到)。

    java 复制代码
    @MapperScan(basePackages = {"com.xxx.*.mapper", "com.xxx.util.*.mapper"})
  3. 与 auth-server 共享同一个 Redis(二次验证的「已验证」状态要跨服务读到)。

四、可选配置(application.yml,不给就用默认)

yaml 复制代码
mfa:
  pending:
    ttlSeconds: 300   # 两步登录凭证有效期(秒)
  # 其余 totp/recovery/rateLimit 项主要给 auth-server 用,消费方一般不用配

五、特殊服务:查不到 auth_user_basic_t 时覆盖默认

若某服务(独立 DB / 不连 auth 库)无法直接查该表,自定义一个 MfaStatusProvider bean,MfaAutoConfiguration 的默认实现会自动让位

java 复制代码
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
相关推荐
ZGG0031 小时前
线程池详解:从 7 大参数到生产避坑
java·数据库·后端
迪康Defender1 小时前
公用电脑责任追溯难?迪康端点安全一体化管理系统用户模式详解
java·运维·开发语言·网络·其他·安全
京师20万禁军教头2 小时前
47-常用类-八大包装类(Wrapper Classes)
java
come112342 小时前
剪映零基础教程
java·linux·运维
16月6日-晴2 小时前
Java面向对象——接口
java·开发语言
苏生Susheng2 小时前
【软件实施】Windows 服务器运维实战
java·运维·服务器·windows·spring boot·javaweb·实施
Java小白笔记2 小时前
Java 实现 ZIP 压缩包生成方案
java·开发语言·网络·7-zip
霸道流氓气质3 小时前
Spring AI 多模态开发指南:图片理解与语音合成
java·人工智能·spring
en.en..3 小时前
Linux mmap 内存映射深度解析:基于帧缓冲 /dev/fb0
java·服务器·前端