package com.tcm.training.admin.app.auth.service;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.tcm.training.admin.app.auth.dto.AppSmsCodeSendRequest;
|
import com.tcm.training.admin.app.auth.dto.AppSmsLoginRequest;
|
import com.tcm.training.admin.app.auth.support.StpAppUserUtil;
|
import com.tcm.training.admin.app.auth.vo.AppLoginResponse;
|
import com.tcm.training.admin.app.auth.vo.AppLoginUserVO;
|
import com.tcm.training.admin.app.auth.vo.AppSmsCodeSendResponse;
|
import com.tcm.training.admin.member.entity.AppUser;
|
import com.tcm.training.admin.member.mapper.UserMapper;
|
import cn.dev33.satoken.stp.SaTokenInfo;
|
import org.springframework.stereotype.Service;
|
|
import java.util.regex.Pattern;
|
|
/**
|
* APP 短信验证码登录服务。
|
*/
|
@Service
|
public class AppAuthService {
|
|
private static final Pattern PHONE_PATTERN = Pattern.compile("^1\\d{10}$");
|
|
private final UserMapper userMapper;
|
private final AppSmsCodeService appSmsCodeService;
|
|
/**
|
* 注入 APP 用户查询能力与短信验证码服务。
|
*/
|
public AppAuthService(UserMapper userMapper, AppSmsCodeService appSmsCodeService) {
|
this.userMapper = userMapper;
|
this.appSmsCodeService = appSmsCodeService;
|
}
|
|
/**
|
* 为已注册 APP 用户生成登录验证码。
|
*/
|
public AppSmsCodeSendResponse sendLoginCode(AppSmsCodeSendRequest request) {
|
String phone = normalizePhone(request.getPhone());
|
requireEnabledUserByPhone(phone);
|
return appSmsCodeService.createLoginCode(phone);
|
}
|
|
/**
|
* 使用短信验证码完成 APP 用户登录。
|
*/
|
public AppLoginResponse smsLogin(AppSmsLoginRequest request) {
|
String phone = normalizePhone(request.getPhone());
|
AppUser user = requireEnabledUserByPhone(phone);
|
appSmsCodeService.validateLoginCode(phone, normalizeCode(request.getCode()));
|
|
StpAppUserUtil.login(user.getId());
|
SaTokenInfo tokenInfo = StpAppUserUtil.getTokenInfo();
|
return new AppLoginResponse(
|
tokenInfo.getTokenValue(),
|
"Bearer",
|
tokenInfo.getTokenTimeout(),
|
buildLoginUser(user)
|
);
|
}
|
|
/**
|
* 将 APP 用户实体转换为登录响应中的用户摘要。
|
*/
|
private AppLoginUserVO buildLoginUser(AppUser user) {
|
AppLoginUserVO loginUser = new AppLoginUserVO();
|
loginUser.setId(user.getId());
|
loginUser.setNickname(resolveNickname(user));
|
loginUser.setPhone(user.getPhone());
|
loginUser.setAvatar(user.getAvatar());
|
loginUser.setType(user.getType());
|
loginUser.setStatus(user.getStatus());
|
loginUser.setClinicId(user.getClinicId());
|
loginUser.setMemberExpireAt(user.getMemberExpireAt());
|
return loginUser;
|
}
|
|
/**
|
* 按手机号查询并校验 APP 用户状态。
|
*/
|
private AppUser requireEnabledUserByPhone(String phone) {
|
AppUser user = userMapper.selectOne(new LambdaQueryWrapper<AppUser>()
|
.eq(AppUser::getPhone, phone)
|
.eq(AppUser::getDeleted, 0)
|
.last("limit 1"));
|
if (user == null) {
|
throw new IllegalArgumentException("账号不存在,请先注册");
|
}
|
if (user.getStatus() == null || user.getStatus() != 1) {
|
throw new IllegalArgumentException("账号已被禁用");
|
}
|
return user;
|
}
|
|
/**
|
* 归一化并校验手机号格式。
|
*/
|
private String normalizePhone(String phone) {
|
String normalized = trimToNull(phone);
|
if (normalized == null || !PHONE_PATTERN.matcher(normalized).matches()) {
|
throw new IllegalArgumentException("请输入正确的手机号");
|
}
|
return normalized;
|
}
|
|
/**
|
* 归一化并校验验证码。
|
*/
|
private String normalizeCode(String code) {
|
String normalized = trimToNull(code);
|
if (normalized == null) {
|
throw new IllegalArgumentException("请输入验证码");
|
}
|
return normalized;
|
}
|
|
/**
|
* 优先使用昵称,缺失时回退到手机号作为展示名称。
|
*/
|
private String resolveNickname(AppUser user) {
|
String nickname = trimToNull(user.getNickname());
|
return nickname == null ? user.getPhone() : nickname;
|
}
|
|
/**
|
* 将空白字符串归一化为 null。
|
*/
|
private String trimToNull(String value) {
|
if (value == null) {
|
return null;
|
}
|
String trimmed = value.trim();
|
return trimmed.isEmpty() ? null : trimmed;
|
}
|
}
|