From 2a880df691d1891facb9616fabe7d82d92c6acbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Sun, 31 May 2026 11:30:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(auth):=20=E6=96=B0=E5=A2=9E=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E8=80=85=E7=9F=AD=E4=BF=A1=E9=AA=8C=E8=AF=81=E7=A0=81?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加根据手机号查询最近登录开发者账号接口,忽略租户隔离 - 实现开发者登录时手机号无注册时的错误提示 - 在登录流程中支持场景参数,区分开发者登录逻辑 - 新增开发者短信验证码登录API及相关校验逻辑 - 将开发者短信登录接口加入安全配置免验证路径 - 在User实体中添加isDeveloper字段标识开发者账号 - 记录登录操作日志,包含成功与失败原因 - 支持token有效期配置优先取缓存中的注册配置 --- .../common/core/security/SecurityConfig.java | 1 + .../system/controller/MainController.java | 65 +++++++++++++++++++ .../gxwebsoft/common/system/entity/User.java | 3 + .../common/system/mapper/UserMapper.java | 9 +++ .../common/system/mapper/xml/UserMapper.xml | 24 +++++++ .../common/system/service/UserService.java | 8 +++ .../system/service/impl/UserServiceImpl.java | 5 ++ 7 files changed, 115 insertions(+) diff --git a/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java b/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java index d1b31a5..422f48b 100644 --- a/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java +++ b/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java @@ -55,6 +55,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { "/api/sendSmsCaptcha", "/api/loginBySms", "/api/loginBySuperAdminSms", + "/api/loginByDeveloperSms", "/api/system/user/regByPhone", "/api/parseToken/*", "/api/login-alipay/*", diff --git a/src/main/java/com/gxwebsoft/common/system/controller/MainController.java b/src/main/java/com/gxwebsoft/common/system/controller/MainController.java index 1a8eb55..5fce460 100644 --- a/src/main/java/com/gxwebsoft/common/system/controller/MainController.java +++ b/src/main/java/com/gxwebsoft/common/system/controller/MainController.java @@ -469,6 +469,12 @@ public class MainController extends BaseController { return fail("该手机号码未注册超级管理员账号!"); } } + if (param.getScene() != null && param.getScene().equals("developerLogin")) { + final User developer = userService.getLastLoginDeveloperByPhone(param.getPhone()); + if (ObjectUtil.isEmpty(developer)) { + return fail("该手机号码未注册开发者账号!"); + } + } Integer tenantId = getTenantId(); @@ -758,6 +764,65 @@ public class MainController extends BaseController { return success("登录成功", new LoginResult(access_token, user)); } + @Operation(summary = "开发者短信验证码登录") + @PostMapping("/loginByDeveloperSms") + public ApiResult loginByDeveloperSms(@RequestBody LoginParam param, HttpServletRequest request) { + if (param == null) { + return fail("参数不能为空", null); + } + final String phone = param.getPhone(); + if (!CommonUtil.isValidPhoneNumber(phone)) { + return fail("请输入有效的手机号码", null); + } + String code = param.getCode(); + if (StrUtil.isBlank(code)) { + code = param.getSmsCode(); + } + if (StrUtil.isBlank(code)) { + return fail("验证码不能为空", null); + } + + String smsCode = redisUtil.get("code:" + phone); + String devSmsCode = redisUtil.get(CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS); + if (!StrUtil.equals(code, smsCode) && !StrUtil.equals(code, devSmsCode)) { + String message = "验证码不正确"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, null, request); + return fail(message, null); + } + + User user = userService.getLastLoginDeveloperByPhone(phone); + if (user == null) { + String message = "用户不存在"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, null, request); + return fail(message, null); + } + if (!Boolean.TRUE.equals(user.getIsDeveloper())) { + String message = "非开发者账号不允许登录"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, user.getTenantId(), request); + return fail(message, null); + } + if (!user.getStatus().equals(0)) { + String message = "账号被冻结"; + loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_ERROR, message, user.getTenantId(), request); + return fail(message, null); + } + + Long tokenExpireTime = configProperties.getTokenExpireTime(); + final JSONObject register = cacheClient.getSettingInfo("register", user.getTenantId()); + if (register != null) { + final String ExpireTime = register.getString("tokenExpireTime"); + if (ExpireTime != null) { + tokenExpireTime = Long.valueOf(ExpireTime); + } + } + + loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_LOGIN, null, user.getTenantId(), request); + String access_token = JwtUtil.buildToken(new JwtSubject(user.getUsername(), user.getTenantId()), + tokenExpireTime, configProperties.getTokenKey()); + redisUtil.set("access_token:" + user.getUserId(), access_token, tokenExpireTime, TimeUnit.SECONDS); + return success("登录成功", new LoginResult(access_token, user)); + } + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) @Operation(summary = "账号注册") @PostMapping("/register") diff --git a/src/main/java/com/gxwebsoft/common/system/entity/User.java b/src/main/java/com/gxwebsoft/common/system/entity/User.java index 432ae6f..c3cec76 100644 --- a/src/main/java/com/gxwebsoft/common/system/entity/User.java +++ b/src/main/java/com/gxwebsoft/common/system/entity/User.java @@ -199,6 +199,9 @@ public class User implements UserDetails { @Schema(description = "是否超级管理员") private Boolean isSuperAdmin; + @Schema(description = "是否开发者") + private Boolean isDeveloper; + @Schema(description = "租户管理员ID") @TableField(exist = false) private Integer adminId; diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java index 4177d56..b889d0f 100644 --- a/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java +++ b/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java @@ -99,4 +99,13 @@ public interface UserMapper extends BaseMapper { @InterceptorIgnore(tenantLine = "true") User selectLastLoginSuperAdminByPhone(@Param("phone") String phone); + /** + * 根据手机号查询最近登录的开发者账号(忽略租户隔离) + * + * @param phone 手机号 + * @return User + */ + @InterceptorIgnore(tenantLine = "true") + User selectLastLoginDeveloperByPhone(@Param("phone") String phone); + } diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml index 525ee56..770cea7 100644 --- a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml @@ -403,4 +403,28 @@ LIMIT 1 + + + diff --git a/src/main/java/com/gxwebsoft/common/system/service/UserService.java b/src/main/java/com/gxwebsoft/common/system/service/UserService.java index ebc28a6..3b765f5 100644 --- a/src/main/java/com/gxwebsoft/common/system/service/UserService.java +++ b/src/main/java/com/gxwebsoft/common/system/service/UserService.java @@ -134,6 +134,14 @@ public interface UserService extends IService, UserDetailsService { */ User getLastLoginSuperAdminByPhone(String phone); + /** + * 根据手机号查询最近登录的开发者账号(忽略租户隔离) + * + * @param phone 手机号 + * @return 用户信息 + */ + User getLastLoginDeveloperByPhone(String phone); + List pageAll(UserParam param); User getByUserId(String userId); diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java index 44af461..58077b2 100644 --- a/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java @@ -375,6 +375,11 @@ public class UserServiceImpl extends ServiceImpl implements Us return baseMapper.selectLastLoginSuperAdminByPhone(phone); } + @Override + public User getLastLoginDeveloperByPhone(String phone) { + return baseMapper.selectLastLoginDeveloperByPhone(phone); + } + @Override public List pageAll(UserParam param) { return baseMapper.pageRelAll(param);