feat(auth): 新增开发者短信验证码登录功能
- 增加根据手机号查询最近登录开发者账号接口,忽略租户隔离 - 实现开发者登录时手机号无注册时的错误提示 - 在登录流程中支持场景参数,区分开发者登录逻辑 - 新增开发者短信验证码登录API及相关校验逻辑 - 将开发者短信登录接口加入安全配置免验证路径 - 在User实体中添加isDeveloper字段标识开发者账号 - 记录登录操作日志,包含成功与失败原因 - 支持token有效期配置优先取缓存中的注册配置
This commit is contained in:
@@ -55,6 +55,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
"/api/sendSmsCaptcha",
|
"/api/sendSmsCaptcha",
|
||||||
"/api/loginBySms",
|
"/api/loginBySms",
|
||||||
"/api/loginBySuperAdminSms",
|
"/api/loginBySuperAdminSms",
|
||||||
|
"/api/loginByDeveloperSms",
|
||||||
"/api/system/user/regByPhone",
|
"/api/system/user/regByPhone",
|
||||||
"/api/parseToken/*",
|
"/api/parseToken/*",
|
||||||
"/api/login-alipay/*",
|
"/api/login-alipay/*",
|
||||||
|
|||||||
@@ -469,6 +469,12 @@ public class MainController extends BaseController {
|
|||||||
return fail("该手机号码未注册超级管理员账号!");
|
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();
|
Integer tenantId = getTenantId();
|
||||||
@@ -758,6 +764,65 @@ public class MainController extends BaseController {
|
|||||||
return success("登录成功", new LoginResult(access_token, user));
|
return success("登录成功", new LoginResult(access_token, user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "开发者短信验证码登录")
|
||||||
|
@PostMapping("/loginByDeveloperSms")
|
||||||
|
public ApiResult<LoginResult> 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)
|
@Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE)
|
||||||
@Operation(summary = "账号注册")
|
@Operation(summary = "账号注册")
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
|
|||||||
@@ -199,6 +199,9 @@ public class User implements UserDetails {
|
|||||||
@Schema(description = "是否超级管理员")
|
@Schema(description = "是否超级管理员")
|
||||||
private Boolean isSuperAdmin;
|
private Boolean isSuperAdmin;
|
||||||
|
|
||||||
|
@Schema(description = "是否开发者")
|
||||||
|
private Boolean isDeveloper;
|
||||||
|
|
||||||
@Schema(description = "租户管理员ID")
|
@Schema(description = "租户管理员ID")
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private Integer adminId;
|
private Integer adminId;
|
||||||
|
|||||||
@@ -99,4 +99,13 @@ public interface UserMapper extends BaseMapper<User> {
|
|||||||
@InterceptorIgnore(tenantLine = "true")
|
@InterceptorIgnore(tenantLine = "true")
|
||||||
User selectLastLoginSuperAdminByPhone(@Param("phone") String phone);
|
User selectLastLoginSuperAdminByPhone(@Param("phone") String phone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据手机号查询最近登录的开发者账号(忽略租户隔离)
|
||||||
|
*
|
||||||
|
* @param phone 手机号
|
||||||
|
* @return User
|
||||||
|
*/
|
||||||
|
@InterceptorIgnore(tenantLine = "true")
|
||||||
|
User selectLastLoginDeveloperByPhone(@Param("phone") String phone);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,4 +403,28 @@
|
|||||||
LIMIT 1
|
LIMIT 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- 根据手机号查询最近登录的开发者账号(忽略租户隔离) -->
|
||||||
|
<select id="selectLastLoginDeveloperByPhone" resultType="com.gxwebsoft.common.system.entity.User">
|
||||||
|
SELECT u.*
|
||||||
|
FROM sys_user u
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT tenant_id,
|
||||||
|
username,
|
||||||
|
MAX(create_time) AS last_login_time
|
||||||
|
FROM sys_login_record
|
||||||
|
WHERE login_type = 0
|
||||||
|
GROUP BY tenant_id, username
|
||||||
|
) lr ON lr.tenant_id = u.tenant_id
|
||||||
|
AND (lr.username = u.username OR lr.username = u.phone)
|
||||||
|
WHERE u.deleted = 0
|
||||||
|
AND u.status = 0
|
||||||
|
AND u.phone = #{phone}
|
||||||
|
AND u.is_developer = 1
|
||||||
|
ORDER BY lr.last_login_time DESC,
|
||||||
|
u.update_time DESC,
|
||||||
|
u.create_time DESC,
|
||||||
|
u.user_id DESC
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -134,6 +134,14 @@ public interface UserService extends IService<User>, UserDetailsService {
|
|||||||
*/
|
*/
|
||||||
User getLastLoginSuperAdminByPhone(String phone);
|
User getLastLoginSuperAdminByPhone(String phone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据手机号查询最近登录的开发者账号(忽略租户隔离)
|
||||||
|
*
|
||||||
|
* @param phone 手机号
|
||||||
|
* @return 用户信息
|
||||||
|
*/
|
||||||
|
User getLastLoginDeveloperByPhone(String phone);
|
||||||
|
|
||||||
List<User> pageAll(UserParam param);
|
List<User> pageAll(UserParam param);
|
||||||
|
|
||||||
User getByUserId(String userId);
|
User getByUserId(String userId);
|
||||||
|
|||||||
@@ -375,6 +375,11 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
|||||||
return baseMapper.selectLastLoginSuperAdminByPhone(phone);
|
return baseMapper.selectLastLoginSuperAdminByPhone(phone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getLastLoginDeveloperByPhone(String phone) {
|
||||||
|
return baseMapper.selectLastLoginDeveloperByPhone(phone);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<User> pageAll(UserParam param) {
|
public List<User> pageAll(UserParam param) {
|
||||||
return baseMapper.pageRelAll(param);
|
return baseMapper.pageRelAll(param);
|
||||||
|
|||||||
Reference in New Issue
Block a user