375 lines
13 KiB
Java
375 lines
13 KiB
Java
package com.ruoyi.system.ControllerUtil;
|
||
|
||
import com.ruoyi.common.core.domain.AjaxResult;
|
||
import com.ruoyi.system.domain.Users;
|
||
import com.ruoyi.system.service.IUsersService;
|
||
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
|
||
import static com.ruoyi.common.core.domain.AjaxResult.error;
|
||
import static com.ruoyi.common.core.domain.AjaxResult.success;
|
||
|
||
/**
|
||
* 小程序登录工具类
|
||
*
|
||
* 提供微信小程序登录相关的工具方法
|
||
* 主要功能:
|
||
* 1. 参数验证和提取
|
||
* 2. 微信openid获取
|
||
* 3. 用户手机号获取
|
||
* 4. 用户创建和更新
|
||
* 5. 登录响应构建
|
||
*
|
||
* @author Mr. Zhang Pan
|
||
* @date 2025-01-03
|
||
* @version 1.0
|
||
*/
|
||
public class AppletLoginUtil {
|
||
|
||
/**
|
||
* 执行微信登录完整流程
|
||
*
|
||
* @param params 登录参数
|
||
* @param usersService 用户服务
|
||
* @return 登录结果
|
||
*/
|
||
public static AjaxResult executeWechatLogin(Map<String, Object> params, IUsersService usersService) {
|
||
try {
|
||
// 1. 参数验证
|
||
String jsCode = validateAndExtractParam(params, "usercode", "微信登录code不能为空");
|
||
String phoneCode = validateAndExtractParam(params, "code", "手机号授权code不能为空");
|
||
|
||
// 2. 获取微信openid
|
||
String openid = getWechatOpenid(jsCode);
|
||
if (openid == null) {
|
||
return error("获取微信openid失败,请重试");
|
||
}
|
||
|
||
// 3. 检查用户是否已存在
|
||
Users existingUser = usersService.selectUsersByOpenid(openid);
|
||
if (existingUser != null) {
|
||
existingUser.setRemember_token(existingUser.getRememberToken());
|
||
return buildSuccessResponse(existingUser, false);
|
||
}
|
||
|
||
// 4. 新用户处理:获取手机号并创建用户
|
||
String phoneNumber = getPhoneNumber(phoneCode);
|
||
if (phoneNumber == null) {
|
||
return error("获取手机号失败,请重新授权");
|
||
}
|
||
|
||
// 5. 创建或更新用户
|
||
Users user = createOrUpdateUser(openid, phoneNumber, usersService);
|
||
user.setRemember_token(user.getRememberToken());
|
||
return buildSuccessResponse(user, true);
|
||
|
||
} catch (IllegalArgumentException e) {
|
||
return error(e.getMessage());
|
||
} catch (Exception e) {
|
||
System.err.println("微信登录异常:" + e.getMessage());
|
||
e.printStackTrace();
|
||
return error("微信登录失败,请稍后重试");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 验证并提取请求参数
|
||
*
|
||
* @param params 参数Map
|
||
* @param key 参数键
|
||
* @param errorMessage 错误信息
|
||
* @return 参数值
|
||
* @throws IllegalArgumentException 参数无效时抛出
|
||
*/
|
||
public static String validateAndExtractParam(Map<String, Object> params, String key, String errorMessage) {
|
||
Object value = params.get(key);
|
||
if (value == null || value.toString().trim().isEmpty()) {
|
||
throw new IllegalArgumentException(errorMessage);
|
||
}
|
||
return value.toString().trim();
|
||
}
|
||
|
||
/**
|
||
* 获取微信openid
|
||
*
|
||
* @param jsCode 微信小程序登录code
|
||
* @return openid或null
|
||
*/
|
||
public static String getWechatOpenid(String jsCode) {
|
||
try {
|
||
Map<String, Object> openidResult = WechatApiUtil.getWechatUserOpenidInfo(jsCode);
|
||
|
||
if (!(Boolean) openidResult.get("success")) {
|
||
System.err.println("获取openid失败:" + openidResult.get("errorMsg"));
|
||
return null;
|
||
}
|
||
|
||
String openid = (String) openidResult.get("openid");
|
||
if (openid == null || openid.trim().isEmpty()) {
|
||
System.err.println("微信API返回的openid为空");
|
||
return null;
|
||
}
|
||
|
||
System.out.println("成功获取微信openid:" + openid.substring(0, 8) + "...");
|
||
return openid;
|
||
|
||
} catch (Exception e) {
|
||
System.err.println("获取微信openid异常:" + e.getMessage());
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取用户手机号
|
||
*
|
||
* @param phoneCode 手机号授权code
|
||
* @return 手机号或null
|
||
*/
|
||
public static String getPhoneNumber(String phoneCode) {
|
||
try {
|
||
Map<String, Object> phoneResult = WechatApiUtil.getPhoneNumberByCode(phoneCode);
|
||
|
||
if (!(Boolean) phoneResult.get("success")) {
|
||
System.err.println("获取手机号失败:" + phoneResult.get("errorMsg"));
|
||
return null;
|
||
}
|
||
|
||
Map<String, Object> phoneInfo = (Map<String, Object>) phoneResult.get("phone_info");
|
||
if (phoneInfo == null) {
|
||
System.err.println("微信API返回的手机号信息为空");
|
||
return null;
|
||
}
|
||
|
||
String phoneNumber = (String) phoneInfo.get("phoneNumber");
|
||
if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
|
||
System.err.println("微信API返回的手机号为空");
|
||
return null;
|
||
}
|
||
|
||
System.out.println("成功获取用户手机号:" + phoneNumber.substring(0, 3) + "****" + phoneNumber.substring(7));
|
||
return phoneNumber;
|
||
|
||
} catch (Exception e) {
|
||
System.err.println("获取用户手机号异常:" + e.getMessage());
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建或更新用户
|
||
*
|
||
* @param openid 微信openid
|
||
* @param phoneNumber 手机号
|
||
* @param usersService 用户服务
|
||
* @return 用户对象
|
||
* @throws Exception 操作失败时抛出
|
||
*/
|
||
public static Users createOrUpdateUser(String openid, String phoneNumber, IUsersService usersService) throws Exception {
|
||
// 1. 生成用户token
|
||
String token = WechatApiUtil.generateUserToken(openid);
|
||
if (token == null || token.trim().isEmpty()) {
|
||
throw new Exception("生成用户token失败");
|
||
}
|
||
|
||
// 2. 检查手机号是否已存在
|
||
Users existingUserByPhone = usersService.selectUsersByPhone(phoneNumber);
|
||
|
||
if (existingUserByPhone != null) {
|
||
// 3. 更新已有用户的openid和token
|
||
return updateExistingUser(existingUserByPhone, openid, token, usersService);
|
||
} else {
|
||
// 4. 创建新用户
|
||
return createNewUser(openid, phoneNumber, token, usersService);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新已有用户信息
|
||
*
|
||
* @param user 已有用户
|
||
* @param openid 微信openid
|
||
* @param token 新token
|
||
* @param usersService 用户服务
|
||
* @return 更新后的用户
|
||
* @throws Exception 更新失败时抛出
|
||
*/
|
||
public static Users updateExistingUser(Users user, String openid, String token, IUsersService usersService) throws Exception {
|
||
try {
|
||
user.setOpenid(openid);
|
||
user.setRememberToken(token);
|
||
|
||
int updateResult = usersService.updateUsers(user);
|
||
if (updateResult <= 0) {
|
||
throw new Exception("更新用户信息失败");
|
||
}
|
||
|
||
System.out.println("成功更新用户信息,用户ID:" + user.getId());
|
||
return user;
|
||
|
||
} catch (Exception e) {
|
||
System.err.println("更新用户信息异常:" + e.getMessage());
|
||
throw new Exception("更新用户信息失败:" + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建新用户
|
||
*
|
||
* @param openid 微信openid
|
||
* @param phoneNumber 手机号
|
||
* @param token 用户token
|
||
* @param usersService 用户服务
|
||
* @return 新创建的用户
|
||
* @throws Exception 创建失败时抛出
|
||
*/
|
||
public static Users createNewUser(String openid, String phoneNumber, String token, IUsersService usersService) throws Exception {
|
||
try {
|
||
Users newUser = new Users();
|
||
newUser.setPhone(phoneNumber);
|
||
newUser.setRememberToken(token);
|
||
newUser.setName("微信用户");
|
||
newUser.setOpenid(openid);
|
||
newUser.setAvatar("/default/user_avatar.jpeg");
|
||
newUser.setType("1");
|
||
newUser.setStatus(1);
|
||
newUser.setIsWork(0);
|
||
|
||
int insertResult = usersService.insertUsers(newUser);
|
||
if (insertResult <= 0) {
|
||
throw new Exception("创建用户记录失败");
|
||
}
|
||
|
||
System.out.println("成功创建新用户,手机号:" + phoneNumber.substring(0, 3) + "****" + phoneNumber.substring(7));
|
||
return newUser;
|
||
|
||
} catch (Exception e) {
|
||
System.err.println("创建新用户异常:" + e.getMessage());
|
||
throw new Exception("创建用户失败:" + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 构建成功响应
|
||
*
|
||
* @param user 用户对象
|
||
* @param isNewUser 是否为新用户
|
||
* @return 响应结果
|
||
*/
|
||
public static AjaxResult buildSuccessResponse(Users user, boolean isNewUser) {
|
||
try {
|
||
// 设置返回字段
|
||
user.setRemember_token(user.getRememberToken());
|
||
|
||
// 构建响应数据
|
||
Map<String, Object> responseData = new HashMap<>();
|
||
responseData.put("user", user);
|
||
responseData.put("isNewUser", isNewUser);
|
||
responseData.put("loginTime", System.currentTimeMillis());
|
||
responseData.put("message", isNewUser ? "注册成功" : "登录成功");
|
||
|
||
System.out.println((isNewUser ? "用户注册成功" : "用户登录成功") + ",用户ID:" + user.getId());
|
||
return success(responseData);
|
||
|
||
} catch (Exception e) {
|
||
System.err.println("构建响应数据异常:" + e.getMessage());
|
||
return error("登录成功但返回数据异常");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 验证用户token并获取用户信息
|
||
*
|
||
* @param token 用户token
|
||
* @param usersService 用户服务
|
||
* @return 验证结果
|
||
*/
|
||
public static Map<String, Object> validateUserToken(String token, IUsersService usersService) {
|
||
Map<String, Object> result = new HashMap<>();
|
||
|
||
try {
|
||
if (token == null || token.trim().isEmpty()) {
|
||
result.put("valid", false);
|
||
result.put("message", "token不能为空");
|
||
return result;
|
||
}
|
||
|
||
// 验证token格式
|
||
if (!WechatApiUtil.isValidTokenFormat(token.trim())) {
|
||
result.put("valid", false);
|
||
result.put("message", "token格式无效");
|
||
return result;
|
||
}
|
||
|
||
// 查询用户信息
|
||
Users user = usersService.selectUsersByRememberToken(token.trim());
|
||
if (user == null) {
|
||
result.put("valid", false);
|
||
result.put("message", "token无效或用户不存在");
|
||
return result;
|
||
}
|
||
|
||
// 检查用户状态
|
||
if (user.getStatus() == null || user.getStatus() != 1) {
|
||
result.put("valid", false);
|
||
result.put("message", "用户账号已被禁用");
|
||
return result;
|
||
}
|
||
|
||
// 设置返回字段并过滤敏感信息
|
||
user.setRemember_token(user.getRememberToken());
|
||
|
||
result.put("valid", true);
|
||
result.put("user", user);
|
||
result.put("message", "token验证成功");
|
||
|
||
} catch (Exception e) {
|
||
result.put("valid", false);
|
||
result.put("message", "token验证异常:" + e.getMessage());
|
||
System.err.println("验证用户token异常:" + e.getMessage());
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 获取并验证请求头中的token
|
||
*
|
||
* @param authHeader Authorization请求头
|
||
* @param tokenHeader token请求头
|
||
* @return 提取的token或null
|
||
*/
|
||
public static String extractToken(String authHeader, String tokenHeader) {
|
||
String token = tokenHeader;
|
||
|
||
// 如果token头为空,尝试从Authorization头获取
|
||
if (token == null || token.trim().isEmpty()) {
|
||
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
||
token = authHeader.substring(7);
|
||
}
|
||
}
|
||
|
||
return (token != null && !token.trim().isEmpty()) ? token.trim() : null;
|
||
}
|
||
|
||
/**
|
||
* 构建登录失败响应
|
||
*
|
||
* @param message 失败信息
|
||
* @return 失败响应
|
||
*/
|
||
public static AjaxResult buildFailureResponse(String message) {
|
||
return error("登录失败:" + message);
|
||
}
|
||
|
||
/**
|
||
* 构建参数错误响应
|
||
*
|
||
* @param paramName 参数名
|
||
* @return 错误响应
|
||
*/
|
||
public static AjaxResult buildParamErrorResponse(String paramName) {
|
||
return error("参数错误:" + paramName + " 不能为空或格式不正确");
|
||
}
|
||
}
|