根据手机查询用户,新增登录逻辑验证

This commit is contained in:
2025-07-05 13:28:32 +08:00
parent f2edb79585
commit 86d4b6b707
13 changed files with 713 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
package com.ruoyi.fadapp.service;
import com.ruoyi.fadapp.domain.vo.LoginResultVo;
/**
* FAD APP认证服务接口
*
* @author ruoyi
*/
public interface IFadAppAuthService {
/**
* 发送验证码
*
* @param phone 手机号
*/
void sendCode(String phone);
/**
* 验证码登录
*
* @param phone 手机号
* @param code 验证码
* @return 登录结果
*/
LoginResultVo loginByCode(String phone, String code);
/**
* 退出登录
*
* @param token 访问令牌
*/
void logout(String token);
}

View File

@@ -0,0 +1,39 @@
package com.ruoyi.fadapp.service;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.fadapp.domain.vo.FadAppUserVo;
/**
* FAD APP用户管理Service接口
*
* @author ruoyi
*/
public interface IFadAppUserService {
/**
* 查询用户列表
*/
TableDataInfo<FadAppUserVo> queryUserList(FadAppUserVo bo, PageQuery pageQuery);
/**
* 获取用户详细信息
*/
FadAppUserVo getUserInfo(Long userId);
/**
* 根据手机号获取用户信息
*
* @param phone 手机号
* @return 用户信息
*/
SysUser getUserByPhone(String phone);
/**
* 获取用户统计信息
*
* @return 统计信息
*/
Object getUserStats();
}

View File

@@ -0,0 +1,167 @@
package com.ruoyi.fadapp.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.RandomUtil;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.DeviceType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.fadapp.domain.vo.LoginResultVo;
import com.ruoyi.fadapp.service.IFadAppAuthService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.SysPermissionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.Duration;
/**
* FAD APP认证服务实现类
*
* @author ruoyi
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class FadAppAuthServiceImpl implements IFadAppAuthService {
private final ISysUserService userService;
private final RedisUtils redisUtils;
private final SysPermissionService permissionService;
/**
* 验证码缓存前缀
*/
private static final String CODE_PREFIX = "fadapp:code:";
/**
* 验证码过期时间(分钟)
*/
private static final int CODE_EXPIRE_MINUTES = 5;
/**
* 固定验证码(开发环境使用)
*/
private static final String FIXED_CODE = "666666";
@Override
public void sendCode(String phone) {
// 验证手机号格式
if (!phone.matches("^1[3-9]\\d{9}$")) {
throw new ServiceException("手机号格式不正确");
}
// 生成验证码(开发环境使用固定验证码)
String code = FIXED_CODE;
// 存储验证码到Redis5分钟过期
String key = CODE_PREFIX + phone;
redisUtils.setCacheObject(key, code, Duration.ofMinutes(CODE_EXPIRE_MINUTES));
// 记录日志(实际项目中这里会调用短信服务)
log.info("向手机号 {} 发送验证码: {}", phone, code);
}
@Override
public LoginResultVo loginByCode(String phone, String code) {
// 验证手机号格式
if (!phone.matches("^1[3-9]\\d{9}$")) {
throw new ServiceException("手机号格式不正确");
}
// 验证验证码格式
if (!code.matches("^\\d{6}$")) {
throw new ServiceException("验证码格式不正确");
}
// 从Redis获取存储的验证码
String key = CODE_PREFIX + phone;
String storedCode = redisUtils.getCacheObject(key);
if (storedCode == null) {
throw new ServiceException("验证码已过期,请重新获取");
}
if (!storedCode.equals(code)) {
throw new ServiceException("验证码不正确");
}
// 验证码验证通过删除Redis中的验证码
redisUtils.deleteObject(key);
// 查找或创建用户
SysUser user = findOrCreateUser(phone);
// 构建登录用户信息
LoginUser loginUser = buildLoginUser(user);
// 使用原来的登录方式生成token
LoginHelper.loginByDevice(loginUser, DeviceType.APP);
String token = StpUtil.getTokenValue();
// 构建登录结果
LoginResultVo result = new LoginResultVo();
result.setToken(token);
result.setUserId(user.getUserId());
result.setUserName(user.getUserName());
result.setNickName(user.getNickName());
result.setPhonenumber(user.getPhonenumber());
result.setAvatar(user.getAvatar());
result.setDeptId(user.getDeptId());
// 这里可以设置部门名称,需要查询部门信息
return result;
}
@Override
public void logout(String token) {
// 清除token这里可以根据实际使用的JWT库来实现
// 如果使用Sa-Token可以调用 StpUtil.logout()
StpUtil.logout();
}
/**
* 查找或创建用户
*/
private SysUser findOrCreateUser(String phone) {
// 先查找用户
SysUser user = userService.selectUserByPhonenumber(phone);
if (user == null) {
// 用户不存在,创建新用户
user = new SysUser();
user.setUserName(phone); // 用户名使用手机号
user.setNickName("用户" + phone.substring(7)); // 昵称使用手机号后4位
user.setPhonenumber(phone);
user.setPassword("123456"); // 默认密码,实际项目中应该生成随机密码
user.setStatus("0"); // 正常状态
// 插入用户
userService.insertUser(user);
// 重新查询用户信息
user = userService.selectUserByPhonenumber(phone);
}
return user;
}
/**
* 构建登录用户
*/
private LoginUser buildLoginUser(SysUser user) {
LoginUser loginUser = new LoginUser();
loginUser.setUserId(user.getUserId());
loginUser.setDeptId(user.getDeptId());
loginUser.setUsername(user.getUserName());
loginUser.setNickName(user.getNickName());
loginUser.setUserType(user.getUserType());
loginUser.setMenuPermission(permissionService.getMenuPermission(user));
loginUser.setRolePermission(permissionService.getRolePermission(user));
loginUser.setDeptName(user.getDept() != null ? user.getDept().getDeptName() : "");
return loginUser;
}
}

View File

@@ -0,0 +1,80 @@
package com.ruoyi.fadapp.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.fadapp.domain.vo.FadAppUserVo;
import com.ruoyi.fadapp.service.IFadAppUserService;
import com.ruoyi.system.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* FAD APP用户管理Service业务层处理
*
* @author ruoyi
*/
@RequiredArgsConstructor
@Service
public class FadAppUserServiceImpl implements IFadAppUserService {
private final SysUserMapper userMapper;
/**
* 查询用户列表
*/
@Override
public TableDataInfo<FadAppUserVo> queryUserList(FadAppUserVo bo, PageQuery pageQuery) {
QueryWrapper<SysUser> lqw = buildQueryWrapper(bo);
Page<SysUser> result = userMapper.selectPage(pageQuery.build(), lqw);
return TableDataInfo.build(BeanUtil.copyToList(result.getRecords(), FadAppUserVo.class));
}
/**
* 获取用户详细信息
*/
@Override
public FadAppUserVo getUserInfo(Long userId) {
SysUser user = userMapper.selectById(userId);
return BeanUtil.toBean(user, FadAppUserVo.class);
}
/**
* 根据手机号获取用户信息
*/
@Override
public SysUser getUserByPhone(String phone) {
return userMapper.selectUserByPhonenumber(phone);
}
/**
* 获取用户统计信息
*/
@Override
public Object getUserStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalUsers", userMapper.selectCount(null));
stats.put("activeUsers", userMapper.selectCount(
Wrappers.<SysUser>lambdaQuery().eq(SysUser::getStatus, "0")
));
return stats;
}
private QueryWrapper<SysUser> buildQueryWrapper(FadAppUserVo bo) {
QueryWrapper<SysUser> lqw = Wrappers.query();
lqw.like(StringUtils.isNotBlank(bo.getUserName()), "user_name", bo.getUserName());
lqw.like(StringUtils.isNotBlank(bo.getNickName()), "nick_name", bo.getNickName());
lqw.like(StringUtils.isNotBlank(bo.getPhonenumber()), "phonenumber", bo.getPhonenumber());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), "status", bo.getStatus());
lqw.eq(bo.getDeptId() != null, "dept_id", bo.getDeptId());
return lqw;
}
}