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

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

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

原理:DefaultMfaStatusProvider 已内置,一次查 auth_user_basic_t 的 totp_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 已验证」写入共享 Redis (mfa:act:{uid}:{action})。

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

-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.* 配置绑定(多数用默认即可)

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

  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
相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
ba_pi3 天前
mysql 查询所有表名并授权
java
ProcessOn官方账号3 天前
java函数式编程--入门基础
java·编程·函数式编程