限流算法从 INCR+EXPIRE 固定窗口升级为 ZSET+Lua 滑动窗口, 新增 IpRateLimitFilter 提供 IP 全局防护(默认 1000次/60s)。 新增 X-RateLimit-Limit/Remaining/Reset 响应头与 Retry-After, 新增 rate-limit.ip.* 配置项控制 IP 全局开关与阈值, @RateLimit 空注解统一走全局配置,消除硬编码。
94 lines
3.7 KiB
Java
94 lines
3.7 KiB
Java
package com.youlai.boot.auth.controller;
|
||
|
||
import com.youlai.boot.auth.model.form.WxMaBindMobileForm;
|
||
import com.youlai.boot.auth.model.form.WxMaPhoneLoginForm;
|
||
import com.youlai.boot.auth.model.vo.WxMaLoginVO;
|
||
import com.youlai.boot.auth.service.WxMaAuthService;
|
||
import com.youlai.boot.common.annotation.Log;
|
||
import com.youlai.boot.common.annotation.RateLimit;
|
||
import com.youlai.boot.common.enums.ActionTypeEnum;
|
||
import com.youlai.boot.common.enums.LogModuleEnum;
|
||
import com.youlai.boot.common.result.Result;
|
||
import com.youlai.boot.framework.security.model.AuthenticationToken;
|
||
import io.swagger.v3.oas.annotations.Operation;
|
||
import io.swagger.v3.oas.annotations.Parameter;
|
||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||
import lombok.RequiredArgsConstructor;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.web.bind.annotation.PostMapping;
|
||
import org.springframework.web.bind.annotation.RequestBody;
|
||
import org.springframework.web.bind.annotation.RequestMapping;
|
||
import org.springframework.web.bind.annotation.RequestParam;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
|
||
import jakarta.validation.Valid;
|
||
|
||
/**
|
||
* 微信小程序认证控制层
|
||
*
|
||
* @author Ray.Hao
|
||
* @since 2.4.0
|
||
*/
|
||
@Tag(name = "13.微信小程序认证")
|
||
@RestController
|
||
@RequestMapping("/api/v1/wxma/auth")
|
||
@RequiredArgsConstructor
|
||
@Slf4j
|
||
public class WxMaAuthController {
|
||
|
||
private final WxMaAuthService wxMaAuthService;
|
||
|
||
/**
|
||
* 静默登录
|
||
* <p>
|
||
* 适用场景:个人小程序、无需手机号的登录场景
|
||
* <ul>
|
||
* <li>已绑定手机号的用户:直接返回 token,登录成功</li>
|
||
* <li>未绑定手机号的用户:返回 openid,需调用绑定手机号接口</li>
|
||
* </ul>
|
||
*/
|
||
@Operation(summary = "静默登录", description = "通过微信 code 登录,已绑定用户直接返回 token,未绑定用户返回 openid 需绑定手机号")
|
||
@PostMapping("/silent-login")
|
||
@Log(module = LogModuleEnum.LOGIN, value = ActionTypeEnum.LOGIN)
|
||
@RateLimit
|
||
public Result<WxMaLoginVO> silentLogin(
|
||
@Parameter(description = "微信登录凭证(wx.login 获取)", required = true, example = "0xxx")
|
||
@RequestParam String code
|
||
) {
|
||
WxMaLoginVO result = wxMaAuthService.silentLogin(code);
|
||
return Result.success(result);
|
||
}
|
||
|
||
/**
|
||
* 手机号快捷登录
|
||
* <p>
|
||
* 适用场景:企业认证小程序(已开通手机号快捷登录权限)
|
||
* <p>
|
||
* 一步完成登录,无需绑定流程,自动创建新用户
|
||
*/
|
||
@Operation(summary = "手机号快捷登录", description = "同时使用微信 code 和手机号授权 code 登录,适用于企业认证小程序")
|
||
@PostMapping("/phone-login")
|
||
@Log(module = LogModuleEnum.LOGIN, value = ActionTypeEnum.LOGIN)
|
||
@RateLimit
|
||
public Result<AuthenticationToken> phoneLogin(@Valid @RequestBody WxMaPhoneLoginForm req) {
|
||
AuthenticationToken result = wxMaAuthService.phoneLogin(req.getLoginCode(), req.getPhoneCode());
|
||
return Result.success(result);
|
||
}
|
||
|
||
/**
|
||
* 绑定手机号
|
||
* <p>
|
||
* 适用场景:静默登录后未绑定手机号的用户
|
||
* <p>
|
||
* 绑定成功后自动完成登录
|
||
*/
|
||
@Operation(summary = "绑定手机号", description = "为静默登录用户绑定手机号,绑定成功后自动登录")
|
||
@PostMapping("/bind-mobile")
|
||
@Log(module = LogModuleEnum.LOGIN, value = ActionTypeEnum.LOGIN)
|
||
@RateLimit
|
||
public Result<AuthenticationToken> bindMobile(@Valid @RequestBody WxMaBindMobileForm req) {
|
||
AuthenticationToken result = wxMaAuthService.bindMobile(req.getOpenid(), req.getMobile(), req.getSmsCode());
|
||
return Result.success(result);
|
||
}
|
||
}
|