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));
|
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 = "检查用户是否存在")
|
@Operation(summary = "检查用户是否存在")
|
||||||
@GetMapping("/existence")
|
@GetMapping("/existence")
|
||||||
public ApiResult<?> existence(ExistenceParam<User> param) {
|
public ApiResult<?> existence(ExistenceParam<User> param) {
|
||||||
|
|||||||
@@ -380,6 +380,17 @@
|
|||||||
ORDER BY a.create_time DESC
|
ORDER BY a.create_time DESC
|
||||||
</select>
|
</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 id="countByPhone" resultType="java.lang.Integer">
|
||||||
SELECT COUNT(1)
|
SELECT COUNT(1)
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ public class LoginParam implements Serializable {
|
|||||||
@Schema(description = "手机号码")
|
@Schema(description = "手机号码")
|
||||||
private String phone;
|
private String phone;
|
||||||
|
|
||||||
|
@Schema(description = "邮箱")
|
||||||
|
private String email;
|
||||||
|
|
||||||
@Schema(description = "短信验证码")
|
@Schema(description = "短信验证码")
|
||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
|
|||||||
@@ -156,6 +156,14 @@ public interface UserService extends IService<User>, UserDetailsService {
|
|||||||
*/
|
*/
|
||||||
List<User> findAccountsByPhone(String phone);
|
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);
|
return baseMapper.selectAccountsByPhone(phone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<User> findAccountsByEmail(String email) {
|
||||||
|
if (StrUtil.isBlank(email)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return baseMapper.selectAccountsByEmail(email);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer countAccountsByPhone(String phone) {
|
public Integer countAccountsByPhone(String phone) {
|
||||||
if (StrUtil.isBlank(phone)) {
|
if (StrUtil.isBlank(phone)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user