|
|
|
@ -7,6 +7,7 @@ import org.springframework.security.authentication.BadCredentialsException; |
|
|
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|
|
|
import org.springframework.security.core.Authentication; |
|
|
|
import org.springframework.stereotype.Component; |
|
|
|
import org.springframework.transaction.annotation.Transactional; |
|
|
|
import com.chenhai.common.constant.CacheConstants; |
|
|
|
import com.chenhai.common.constant.Constants; |
|
|
|
import com.chenhai.common.constant.UserConstants; |
|
|
|
@ -25,12 +26,28 @@ import com.chenhai.common.utils.ip.IpUtils; |
|
|
|
import com.chenhai.framework.manager.AsyncManager; |
|
|
|
import com.chenhai.framework.manager.factory.AsyncFactory; |
|
|
|
import com.chenhai.framework.security.context.AuthenticationContextHolder; |
|
|
|
|
|
|
|
// =================== 新增依赖导入 =================== |
|
|
|
import com.alibaba.fastjson2.JSONObject; |
|
|
|
import com.chenhai.common.core.domain.entity.SysUser; |
|
|
|
import com.chenhai.common.core.domain.model.*; |
|
|
|
import com.chenhai.common.utils.WechatDecryptUtil; |
|
|
|
import com.chenhai.framework.security.exception.WechatNeedBindException; |
|
|
|
import com.chenhai.framework.security.token.PhoneAuthenticationToken; |
|
|
|
import com.chenhai.framework.security.token.WechatAuthenticationToken; |
|
|
|
import com.chenhai.muhu.service.IUserAuthService; |
|
|
|
import com.chenhai.muhu.service.WechatService; |
|
|
|
import com.chenhai.system.service.ISysConfigService; |
|
|
|
import com.chenhai.system.service.ISysUserService; |
|
|
|
|
|
|
|
import java.util.Date; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.Map; |
|
|
|
// ================================================= |
|
|
|
|
|
|
|
/** |
|
|
|
* 登录校验方法 |
|
|
|
* |
|
|
|
* |
|
|
|
* @author ruoyi |
|
|
|
*/ |
|
|
|
@Component |
|
|
|
@ -44,16 +61,27 @@ public class SysLoginService |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private RedisCache redisCache; |
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
private ISysUserService userService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private ISysConfigService configService; |
|
|
|
|
|
|
|
// =================== 新增依赖 =================== |
|
|
|
@Autowired |
|
|
|
private IUserAuthService userAuthService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private WechatService wechatService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private SysPermissionService permissionService; |
|
|
|
// =============================================== |
|
|
|
|
|
|
|
/** |
|
|
|
* 登录验证 |
|
|
|
* |
|
|
|
* 登录验证 - 原有的用户名密码登录 |
|
|
|
* |
|
|
|
* @param username 用户名 |
|
|
|
* @param password 密码 |
|
|
|
* @param code 验证码 |
|
|
|
@ -101,7 +129,7 @@ public class SysLoginService |
|
|
|
|
|
|
|
/** |
|
|
|
* 校验验证码 |
|
|
|
* |
|
|
|
* |
|
|
|
* @param username 用户名 |
|
|
|
* @param code 验证码 |
|
|
|
* @param uuid 唯一标识 |
|
|
|
@ -173,4 +201,213 @@ public class SysLoginService |
|
|
|
{ |
|
|
|
userService.updateLoginInfo(userId, IpUtils.getIpAddr(), DateUtils.getNowDate()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// ==================================================================== |
|
|
|
// =================== 以下是新增的多端登录方法 ======================= |
|
|
|
// ==================================================================== |
|
|
|
|
|
|
|
/** |
|
|
|
* 微信小程序登录 - 多端登录新增 |
|
|
|
* |
|
|
|
* @param code 微信code |
|
|
|
* @param clientType 客户端类型: herdsman-app/vet-app |
|
|
|
* @return 登录结果,包含token或绑定信息 |
|
|
|
*/ |
|
|
|
public Map<String, Object> wechatLogin(String code, String clientType) { |
|
|
|
// 验证参数 |
|
|
|
if (code == null || clientType == null) { |
|
|
|
throw new ServiceException("参数错误"); |
|
|
|
} |
|
|
|
if (!"herdsman-app".equals(clientType) && !"vet-app".equals(clientType)) { |
|
|
|
throw new ServiceException("不支持的客户端类型"); |
|
|
|
} |
|
|
|
|
|
|
|
// 创建认证token |
|
|
|
WechatAuthenticationToken authToken = new WechatAuthenticationToken(code, clientType); |
|
|
|
|
|
|
|
try { |
|
|
|
// 认证 |
|
|
|
Authentication authentication = authenticationManager.authenticate(authToken); |
|
|
|
LoginUser loginUser = (LoginUser) authentication.getPrincipal(); |
|
|
|
|
|
|
|
recordLoginInfo(loginUser.getUserId()); |
|
|
|
|
|
|
|
// 生成token |
|
|
|
String token = tokenService.createToken(loginUser); |
|
|
|
|
|
|
|
Map<String, Object> result = new HashMap<>(); |
|
|
|
result.put("token", token); |
|
|
|
result.put("needBind", false); |
|
|
|
return result; |
|
|
|
|
|
|
|
} catch (WechatNeedBindException e) { |
|
|
|
// 需要绑定手机号 |
|
|
|
Map<String, Object> data = new HashMap<>(); |
|
|
|
data.put("needBind", true); |
|
|
|
data.put("userType", e.getUserType()); // "herdsman" 或 "vet" |
|
|
|
data.put("clientType", e.getClientType()); // "herdsman-app" 或 "vet-app" |
|
|
|
data.put("openid", e.getOpenid()); |
|
|
|
data.put("tempCode", e.getTempCode()); |
|
|
|
data.put("authType", e.getAuthType()); |
|
|
|
data.put("message", "请绑定手机号"); |
|
|
|
return data; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 微信绑定手机号 - 多端登录新增 |
|
|
|
*/ |
|
|
|
@Transactional(rollbackFor = ServiceException.class) |
|
|
|
public Map<String, Object> wechatBind(String encryptedData, String iv, String tempCode, |
|
|
|
String userType, String clientType, String openid, |
|
|
|
String authType, String nickName, String avatarUrl) { |
|
|
|
try { |
|
|
|
// 1. 基本参数验证 |
|
|
|
if (encryptedData == null || iv == null) { |
|
|
|
throw new ServiceException("请通过微信授权获取手机号"); |
|
|
|
} |
|
|
|
|
|
|
|
// 2. 从Redis获取sessionKey |
|
|
|
String sessionKey = redisCache.getCacheObject("wechat:session:" + tempCode); |
|
|
|
if (sessionKey == null) { |
|
|
|
throw new ServiceException("绑定会话已过期,请重新登录"); |
|
|
|
} |
|
|
|
|
|
|
|
// 3. 解密手机号 |
|
|
|
String phone = WechatDecryptUtil.decryptPhone(encryptedData, iv, sessionKey); |
|
|
|
if (phone == null || phone.trim().isEmpty()) { |
|
|
|
throw new ServiceException("获取手机号失败"); |
|
|
|
} |
|
|
|
|
|
|
|
// 4. 查询手机号是否已注册 |
|
|
|
SysUser existingUser = userService.selectUserByPhone(phone); |
|
|
|
|
|
|
|
// 5. 用户不存在,创建新用户 |
|
|
|
if (existingUser == null) { |
|
|
|
String userTypeCode = "herdsman".equals(userType) ? "02" : "01"; |
|
|
|
existingUser = createUserForWechat(phone, userTypeCode, nickName, avatarUrl, clientType); |
|
|
|
} else { |
|
|
|
// 6. 用户已存在,检查用户类型是否匹配 |
|
|
|
String existingUserType = existingUser.getUserType(); |
|
|
|
String expectedUserType = "herdsman".equals(userType) ? "02" : "01"; |
|
|
|
|
|
|
|
if (!existingUserType.equals(expectedUserType)) { |
|
|
|
String existingTypeName = "01".equals(existingUserType) ? "兽医" : "牧户"; |
|
|
|
String expectedTypeName = "01".equals(expectedUserType) ? "兽医" : "牧户"; |
|
|
|
throw new ServiceException("该手机号已注册为" + existingTypeName + ",请使用" + expectedTypeName + "小程序"); |
|
|
|
} |
|
|
|
|
|
|
|
// 7. 用户类型匹配,更新用户信息 |
|
|
|
if (nickName != null) { |
|
|
|
existingUser.setNickName(nickName); |
|
|
|
} |
|
|
|
if (avatarUrl != null) { |
|
|
|
existingUser.setAvatar(avatarUrl); |
|
|
|
} |
|
|
|
userService.updateUser(existingUser); |
|
|
|
} |
|
|
|
|
|
|
|
// 8. 绑定微信openid |
|
|
|
userAuthService.bindAuth(existingUser.getUserId(), authType, openid, sessionKey); |
|
|
|
|
|
|
|
// 9. 创建登录用户 |
|
|
|
LoginUser loginUser = new LoginUser( |
|
|
|
existingUser.getUserId(), |
|
|
|
existingUser.getDeptId(), |
|
|
|
existingUser, |
|
|
|
permissionService.getMenuPermission(existingUser), |
|
|
|
clientType |
|
|
|
); |
|
|
|
|
|
|
|
recordLoginInfo(loginUser.getUserId()); |
|
|
|
|
|
|
|
// 10. 生成token |
|
|
|
String token = tokenService.createToken(loginUser); |
|
|
|
|
|
|
|
// 11. 清理Redis临时数据 |
|
|
|
redisCache.deleteObject("wechat:session:" + tempCode); |
|
|
|
|
|
|
|
Map<String, Object> result = new HashMap<>(); |
|
|
|
result.put("token", token); |
|
|
|
result.put("message", "绑定成功"); |
|
|
|
return result; |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
// 保持原异常处理方式:返回 AjaxResult.error 的字符串 |
|
|
|
throw new ServiceException("绑定失败: " + e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 手机号+密码登录 - 多端登录新增 |
|
|
|
*/ |
|
|
|
public String phoneLogin(String phone, String password, String clientType) { |
|
|
|
// 验证参数 |
|
|
|
if (phone == null || password == null) { |
|
|
|
throw new ServiceException("参数错误"); |
|
|
|
} |
|
|
|
|
|
|
|
// 根据请求来源确定clientType |
|
|
|
String finalClientType = clientType != null ? clientType : "vet-pc"; |
|
|
|
|
|
|
|
// 创建认证token |
|
|
|
PhoneAuthenticationToken authToken = new PhoneAuthenticationToken(phone, password, finalClientType); |
|
|
|
|
|
|
|
// 认证 |
|
|
|
Authentication authentication = authenticationManager.authenticate(authToken); |
|
|
|
LoginUser loginUser = (LoginUser) authentication.getPrincipal(); |
|
|
|
recordLoginInfo(loginUser.getUserId()); |
|
|
|
|
|
|
|
// 生成token |
|
|
|
return tokenService.createToken(loginUser); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 创建用户(微信绑定专用)- 多端登录新增 |
|
|
|
*/ |
|
|
|
private SysUser createUserForWechat(String phone, String userType, |
|
|
|
String nickName, String avatarUrl, String clientType) { |
|
|
|
SysUser user = new SysUser(); |
|
|
|
|
|
|
|
// 生成用户名:前缀 + 手机后4位 + 4位随机数 |
|
|
|
String usernamePrefix = "01".equals(userType) ? "vet_" : "muhu_"; |
|
|
|
Long roleId = "01".equals(userType) ? 4L : 3L; |
|
|
|
user.setRoleIds(new Long[]{roleId}); |
|
|
|
String phoneSuffix = phone.length() > 4 ? phone.substring(phone.length() - 4) : phone; |
|
|
|
String randomSuffix = String.format("%04d", (int)(Math.random() * 10000)); // 4位随机数 |
|
|
|
String username = usernamePrefix + phoneSuffix + "_" + randomSuffix; |
|
|
|
user.setUserName(username); |
|
|
|
|
|
|
|
// 设置昵称:统一为"用户" + 去掉前缀的username部分 |
|
|
|
String displayName = phoneSuffix + "_" + randomSuffix; // 去掉前缀的部分 |
|
|
|
user.setNickName(nickName != null ? nickName : ("用户" + displayName)); |
|
|
|
|
|
|
|
user.setUserType(userType); // "01":兽医, "02":牧户 |
|
|
|
user.setEmail(""); |
|
|
|
user.setPhonenumber(phone); |
|
|
|
user.setSex("0"); |
|
|
|
user.setAvatar(avatarUrl != null ? avatarUrl : ""); |
|
|
|
|
|
|
|
// 设置默认密码(微信登录用不到,但PC端登录需要) |
|
|
|
String defaultPassword = configService.selectConfigByKey("sys.user.initPassword"); |
|
|
|
user.setPassword(com.chenhai.common.utils.SecurityUtils.encryptPassword(defaultPassword)); |
|
|
|
|
|
|
|
user.setStatus("0"); // 正常状态 |
|
|
|
user.setDelFlag("0"); |
|
|
|
user.setCreateTime(new Date()); |
|
|
|
|
|
|
|
// 如果是兽医,设置初始审核状态 |
|
|
|
// if ("01".equals(userType)) { |
|
|
|
// user.setVetStatus("0"); // 0:未提交资质, 1:审核中, 2:已认证, 3:审核不通过 |
|
|
|
// } |
|
|
|
|
|
|
|
userService.insertUser(user); |
|
|
|
|
|
|
|
// 重新查询获取完整用户信息 |
|
|
|
return userService.selectUserByUserName(username); |
|
|
|
} |
|
|
|
|
|
|
|
// ==================================================================== |
|
|
|
// =================== 多端登录方法结束 =============================== |
|
|
|
// ==================================================================== |
|
|
|
} |