feat(auth): 支持邮箱登录及跨租户账号查询
- 在LoginParam中添加邮箱字段支持 - 新增邮箱登录接口,支持跨租户通过邮箱登录功能 - 实现根据邮箱查询所有账号接口,方便多账号选择 - 添加UserService方法支持根据邮箱查询账号 - 在UserMapper.xml中新增根据邮箱查询所有账号SQL语句 - 登录接口增加用户状态和密码校验逻辑 - 设置登录成功后Token生成及Redis缓存同步 - 处理同一邮箱多个租户账号时的租户选择逻辑
This commit is contained in:
@@ -237,6 +237,77 @@ public class MainController extends BaseController {
|
||||
return success("登录成功", new LoginResult(access_token, user));
|
||||
}
|
||||
|
||||
@Operation(summary = "邮箱登录(支持跨租户)")
|
||||
@PostMapping("/loginByEmail")
|
||||
public ApiResult<LoginResult> loginByEmail(@RequestBody LoginParam param, HttpServletRequest request) {
|
||||
// 设置过期时间
|
||||
Long tokenExpireTime = configProperties.getTokenExpireTime();
|
||||
final String email = param.getEmail();
|
||||
final String password = param.getPassword();
|
||||
if (StrUtil.isBlank(email) || StrUtil.isBlank(password)) {
|
||||
return fail("参数不能为空");
|
||||
}
|
||||
// 跨租户:按邮箱查询所有租户下的账号
|
||||
List<User> users = userService.findAccountsByEmail(email);
|
||||
if (users == null || users.isEmpty()) {
|
||||
String message = "用户不存在";
|
||||
loginRecordService.saveAsync(email, LoginRecord.TYPE_ERROR, message, null, request);
|
||||
return fail(message, null);
|
||||
}
|
||||
User user;
|
||||
if (users.size() == 1) {
|
||||
user = users.get(0);
|
||||
} else {
|
||||
// 同一邮箱在多个租户下存在,需用户选择具体租户
|
||||
if (param.getTenantId() == null) {
|
||||
User first = users.get(0);
|
||||
first.setHasAdminsByPhone(true);
|
||||
return success("请选择登录用户", new LoginResult(null, first));
|
||||
}
|
||||
user = users.stream()
|
||||
.filter(u -> u.getTenantId().equals(param.getTenantId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (user == null) {
|
||||
return fail("用户不存在", null);
|
||||
}
|
||||
}
|
||||
if (!user.getStatus().equals(0)) {
|
||||
String message = "账号被冻结";
|
||||
loginRecordService.saveAsync(email, LoginRecord.TYPE_ERROR, message, user.getTenantId(), request);
|
||||
return fail(message, null);
|
||||
}
|
||||
if (!userService.comparePassword(user.getPassword(), password)) {
|
||||
String message = "密码错误";
|
||||
loginRecordService.saveAsync(email, LoginRecord.TYPE_ERROR, message, user.getTenantId(), request);
|
||||
return fail(message, null);
|
||||
}
|
||||
// 登录成功
|
||||
loginRecordService.saveAsync(email, LoginRecord.TYPE_LOGIN, null, user.getTenantId(), request);
|
||||
|
||||
final JSONObject register = cacheClient.getSettingInfo("register", user.getTenantId());
|
||||
if (register != null) {
|
||||
final String ExpireTime = register.getString("tokenExpireTime");
|
||||
if (ExpireTime != null) {
|
||||
tokenExpireTime = Long.valueOf(ExpireTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 签发token
|
||||
String access_token = JwtUtil.buildToken(new JwtSubject(user.getUsername(), user.getTenantId()),
|
||||
tokenExpireTime, configProperties.getTokenKey());
|
||||
// 同步redis
|
||||
redisUtil.set("access_token:" + user.getUserId(), access_token, tokenExpireTime, TimeUnit.SECONDS);
|
||||
return success("登录成功", new LoginResult(access_token, user));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询邮箱下全部账号(跨租户,用于多账号选择)")
|
||||
@GetMapping("/listAdminsByEmailAll")
|
||||
public ApiResult<?> listAdminsByEmailAll(LoginParam param) {
|
||||
final List<User> accounts = userService.findAccountsByEmail(param.getEmail());
|
||||
return success(accounts);
|
||||
}
|
||||
|
||||
@Operation(summary = "检查用户是否存在")
|
||||
@GetMapping("/existence")
|
||||
public ApiResult<?> existence(ExistenceParam<User> param) {
|
||||
|
||||
@@ -380,6 +380,17 @@
|
||||
ORDER BY a.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据邮箱查询所有账号(忽略租户隔离,用于跨租户邮箱登录) -->
|
||||
<select id="selectAccountsByEmail" resultType="com.gxwebsoft.common.system.entity.User">
|
||||
SELECT a.*,
|
||||
t.tenant_name
|
||||
FROM sys_user a
|
||||
LEFT JOIN sys_tenant t ON a.tenant_id = t.tenant_id
|
||||
WHERE a.deleted = 0
|
||||
AND a.email = #{email}
|
||||
ORDER BY a.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据手机号统计账号数量(忽略租户隔离) -->
|
||||
<select id="countByPhone" resultType="java.lang.Integer">
|
||||
SELECT COUNT(1)
|
||||
|
||||
@@ -28,6 +28,9 @@ public class LoginParam implements Serializable {
|
||||
@Schema(description = "手机号码")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "短信验证码")
|
||||
private String code;
|
||||
|
||||
|
||||
@@ -156,6 +156,14 @@ public interface UserService extends IService<User>, UserDetailsService {
|
||||
*/
|
||||
List<User> findAccountsByPhone(String phone);
|
||||
|
||||
/**
|
||||
* 根据邮箱查询所有账号(忽略租户隔离,用于跨租户登录)
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @return List<User>
|
||||
*/
|
||||
List<User> findAccountsByEmail(String email);
|
||||
|
||||
/**
|
||||
* 根据手机号统计账号数量
|
||||
*
|
||||
|
||||
@@ -473,6 +473,14 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
return baseMapper.selectAccountsByPhone(phone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<User> findAccountsByEmail(String email) {
|
||||
if (StrUtil.isBlank(email)) {
|
||||
return null;
|
||||
}
|
||||
return baseMapper.selectAccountsByEmail(email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer countAccountsByPhone(String phone) {
|
||||
if (StrUtil.isBlank(phone)) {
|
||||
|
||||
Reference in New Issue
Block a user