java中可通过自定义注解@requiresecondauth结合aop实现敏感操作前的二次身份校验:定义注解、编写切面拦截并调用redis校验服务验证token,最后在controller方法上声明注解即可。

在 Java 中,可以通过自定义注解 + AOP(面向切面编程)的方式,在敏感操作方法执行前自动触发二次身份校验(如短信验证码、图形验证码、生物识别确认等),实现安全拦截。
一、定义自定义注解 @RequireSecondAuth
声明一个运行时保留、可作用于方法的注解,用于标记需要二次校验的操作:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequireSecondAuth {
String value() default ""; // 可扩展用途,如指定校验类型:SMS、FACE、TOTP
boolean requireUserActive() default true; // 是否要求用户当前处于活跃会话
}
二、编写 AOP 切面进行拦截与校验
使用 Spring AOP 拦截所有被 @RequireSecondAuth 标记的方法,在执行前验证二次身份凭证:
@Aspect
@Component
public class SecondAuthAspect {
@Autowired
private SecondAuthValidator validator; // 自定义校验服务
@Around("@annotation(requireSecondAuth)")
public Object checkSecondAuth(ProceedingJoinPoint joinPoint, RequireSecondAuth requireSecondAuth) throws Throwable {
// 1. 获取当前登录用户(从 SecurityContext 或 ThreadLocal)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated()) {
throw new AccessDeniedException("未登录,无法执行敏感操作");
}
String userId = extractUserId(auth); // 例如:auth.getPrincipal() 转为 String ID
// 2. 从请求上下文(如 HttpServletRequest)提取二次凭证
HttpServletRequest request = getCurrentRequest();
String token = request.getHeader("X-Second-Auth-Token");
String type = requireSecondAuth.value();
// 3. 执行校验逻辑(如 Redis 校验 token 是否有效且未使用过)
if (!validator.validate(userId, token, type)) {
throw new AccessDeniedException("二次身份校验失败,请重新验证");
}
// 4. 校验通过,放行
return joinPoint.proceed();
}
private HttpServletRequest getCurrentRequest() {
RequestAttributes attrs = RequestContextHolder.currentRequestAttributes();
return ((ServletRequestAttributes) attrs).getRequest();
}
private String extractUserId(Authentication auth) {
Object principal = auth.getPrincipal();
if (principal instanceof UserDetails) {
return ((UserDetails) principal).getUsername();
}
return String.valueOf(principal);
}
}
三、实现二次校验服务(示例:基于 Redis 的 Token 校验)
校验服务负责解析并验证客户端传来的二次认证凭证,建议包含时效性、单次性、绑定用户等安全控制:
- 生成 Token 时:将
userId + token存入 Redis,设置 2 分钟过期,并标记为“待验证” - 校验时:检查 token 是否存在、是否匹配 userId、是否已被使用(可用 Redis SETNX 或 Lua 脚本保证原子性)
- 校验成功后立即删除 token,防止重放
- 支持多种类型(如
SMS校验码、FACE_ID设备指纹签名)可由type参数路由
四、在 Controller 方法上使用注解
只需在敏感接口上添加注解,无需侵入业务逻辑:
@PostMapping("/withdraw")
@RequireSecondAuth(value = "SMS", requireUserActive = true)
public Result<string> doWithdraw(@RequestBody WithdrawRequest req) {
// 执行转账等高危操作
return Result.success(accountService.withdraw(req));
}</string>
前端需在调用该接口前,先请求获取二次验证码(如发送短信),再在请求头中带上 X-Second-Auth-Token: abc123。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











