feat(system): 优化微信登录和用户注册逻辑
- 新增微信小程序数据解密工具类 WxMiniProgramDecryptUtil - 重构微信登录接口,支持两种方式获取手机号 - 优化用户注册逻辑,增加租户ID参数 - 更新相关实体类和参数类,以支持新的功能
This commit is contained in:
@@ -63,7 +63,6 @@ public class MybatisPlusConfig {
|
||||
public boolean ignoreTable(String tableName) {
|
||||
return Arrays.asList(
|
||||
"sys_tenant",
|
||||
// "sys_user",
|
||||
"sys_dictionary",
|
||||
"sys_dictionary_data",
|
||||
"sys_user_oauth",
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.gxwebsoft.common.core.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
/**
|
||||
* 微信小程序数据解密工具类
|
||||
* 用于解密微信小程序的encryptedData数据
|
||||
*
|
||||
* @author WebSoft
|
||||
*/
|
||||
public class WxMiniProgramDecryptUtil {
|
||||
|
||||
/**
|
||||
* 解密微信小程序数据
|
||||
*
|
||||
* @param encryptedData 加密的数据
|
||||
* @param sessionKey 会话密钥
|
||||
* @param iv 初始向量
|
||||
* @return 解密后的JSON字符串
|
||||
* @throws Exception 解密失败时抛出异常
|
||||
*/
|
||||
public static String decrypt(String encryptedData, String sessionKey, String iv) throws Exception {
|
||||
// Base64解码
|
||||
byte[] dataByte = Base64.decodeBase64(encryptedData);
|
||||
byte[] keyByte = Base64.decodeBase64(sessionKey);
|
||||
byte[] ivByte = Base64.decodeBase64(iv);
|
||||
|
||||
try {
|
||||
// 如果密钥长度不够,则补齐到32位
|
||||
if (keyByte.length % 16 != 0) {
|
||||
int groups = keyByte.length / 16 + (keyByte.length % 16 != 0 ? 1 : 0);
|
||||
byte[] temp = new byte[groups * 16];
|
||||
System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
|
||||
keyByte = temp;
|
||||
}
|
||||
|
||||
// 初始化
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
|
||||
AlgorithmParameterSpec paramSpec = new IvParameterSpec(ivByte);
|
||||
cipher.init(Cipher.DECRYPT_MODE, spec, paramSpec);
|
||||
|
||||
// 解密
|
||||
byte[] resultByte = cipher.doFinal(dataByte);
|
||||
if (null != resultByte && resultByte.length > 0) {
|
||||
String result = new String(resultByte, StandardCharsets.UTF_8);
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new Exception("微信小程序数据解密失败", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密手机号信息
|
||||
*
|
||||
* @param encryptedData 加密的数据
|
||||
* @param sessionKey 会话密钥
|
||||
* @param iv 初始向量
|
||||
* @return 手机号码,解密失败返回null
|
||||
*/
|
||||
public static String decryptPhoneNumber(String encryptedData, String sessionKey, String iv) {
|
||||
try {
|
||||
String decryptedData = decrypt(encryptedData, sessionKey, iv);
|
||||
if (decryptedData != null) {
|
||||
JSONObject jsonObject = JSON.parseObject(decryptedData);
|
||||
return jsonObject.getString("phoneNumber");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("解密手机号失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密用户信息
|
||||
*
|
||||
* @param encryptedData 加密的数据
|
||||
* @param sessionKey 会话密钥
|
||||
* @param iv 初始向量
|
||||
* @return 解密后的用户信息JSON对象,解密失败返回null
|
||||
*/
|
||||
public static JSONObject decryptUserInfo(String encryptedData, String sessionKey, String iv) {
|
||||
try {
|
||||
String decryptedData = decrypt(encryptedData, sessionKey, iv);
|
||||
if (decryptedData != null) {
|
||||
return JSON.parseObject(decryptedData);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("解密用户信息失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.gxwebsoft.common.system.controller;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@@ -11,6 +12,7 @@ import com.gxwebsoft.common.system.entity.Setting;
|
||||
import com.gxwebsoft.common.system.entity.Tenant;
|
||||
import com.gxwebsoft.common.system.entity.User;
|
||||
import com.gxwebsoft.common.system.param.SettingParam;
|
||||
import com.gxwebsoft.common.system.param.SettingUpdateParam;
|
||||
import com.gxwebsoft.common.system.service.SettingService;
|
||||
import com.gxwebsoft.common.system.service.TenantService;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -76,7 +78,16 @@ public class SettingController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("添加系统设置")
|
||||
@PostMapping()
|
||||
public ApiResult<?> save(@RequestBody Setting setting) {
|
||||
public ApiResult<?> save(@RequestBody SettingUpdateParam settingParam) {
|
||||
final User loginUser = getLoginUser();
|
||||
if(loginUser == null){
|
||||
return fail("请先登录");
|
||||
}
|
||||
|
||||
// 转换为Setting对象
|
||||
Setting setting = convertToSetting(settingParam);
|
||||
setting.setTenantId(loginUser.getTenantId());
|
||||
|
||||
if (settingService.save(setting)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
@@ -87,11 +98,15 @@ public class SettingController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("修改系统设置")
|
||||
@PutMapping()
|
||||
public ApiResult<?> update(@RequestBody Setting setting) {
|
||||
public ApiResult<?> update(@RequestBody SettingUpdateParam settingParam) {
|
||||
final User loginUser = getLoginUser();
|
||||
if(loginUser == null){
|
||||
return fail("请先登录");
|
||||
}
|
||||
|
||||
// 转换为Setting对象
|
||||
Setting setting = convertToSetting(settingParam);
|
||||
setting.setTenantId(loginUser.getTenantId());
|
||||
if (settingService.updateById(setting)) {
|
||||
// 更新系统设置信息到缓存 key = ""
|
||||
String key = setting.getSettingKey().concat(":").concat(loginUser.getTenantId().toString());
|
||||
@@ -178,7 +193,7 @@ public class SettingController extends BaseController {
|
||||
@ApiOperation("根据key更新系统设置")
|
||||
@OperationLog
|
||||
@PutMapping("/updateByKey")
|
||||
public ApiResult<?> updateByKey(@RequestBody Setting setting) {
|
||||
public ApiResult<?> updateByKey(@RequestBody SettingUpdateParam settingParam) {
|
||||
final User loginUser = getLoginUser();
|
||||
if(loginUser == null){
|
||||
return fail("请先登录");
|
||||
@@ -186,6 +201,11 @@ public class SettingController extends BaseController {
|
||||
if(!loginUser.getIsSuperAdmin()){
|
||||
return fail("权限不足");
|
||||
}
|
||||
|
||||
// 转换为Setting对象
|
||||
Setting setting = convertToSetting(settingParam);
|
||||
setting.setTenantId(loginUser.getTenantId());
|
||||
|
||||
return success(settingService.updateByKey(setting));
|
||||
}
|
||||
|
||||
@@ -193,7 +213,10 @@ public class SettingController extends BaseController {
|
||||
@OperationLog
|
||||
@ApiOperation("更新主题皮肤")
|
||||
@PutMapping("/theme")
|
||||
public ApiResult<?> theme(@RequestBody Setting setting) {
|
||||
public ApiResult<?> theme(@RequestBody SettingUpdateParam settingParam) {
|
||||
// 转换为Setting对象
|
||||
Setting setting = convertToSetting(settingParam);
|
||||
setting.setTenantId(getTenantId());
|
||||
String key = "theme:".concat(getTenantId().toString());
|
||||
// 新增
|
||||
final Setting one = settingService.getOne(new LambdaQueryWrapper<Setting>().eq(Setting::getSettingKey, setting.getSettingKey()));
|
||||
@@ -218,4 +241,156 @@ public class SettingController extends BaseController {
|
||||
String key = "theme:".concat(getTenantId().toString());
|
||||
return success("获取成功",redisUtil.get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将SettingUpdateParam转换为Setting对象
|
||||
* 根据settingKey的不同,将相应的字段组装成JSON格式的content
|
||||
*/
|
||||
private Setting convertToSetting(SettingUpdateParam param) {
|
||||
Setting setting = new Setting();
|
||||
setting.setSettingKey(param.getSettingKey());
|
||||
setting.setSortNumber(param.getSortNumber());
|
||||
setting.setComments(param.getComments());
|
||||
setting.setTenantId(param.getTenantId());
|
||||
|
||||
// 如果直接提供了content,则使用content
|
||||
if (StrUtil.isNotBlank(param.getContent())) {
|
||||
setting.setContent(param.getContent());
|
||||
return setting;
|
||||
}
|
||||
|
||||
// 根据settingKey构建相应的JSON content
|
||||
JSONObject contentJson = new JSONObject();
|
||||
|
||||
switch (param.getSettingKey()) {
|
||||
case "mp-weixin":
|
||||
// 微信小程序配置
|
||||
if (StrUtil.isNotBlank(param.getAppId())) {
|
||||
contentJson.put("appId", param.getAppId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getAppSecret())) {
|
||||
contentJson.put("appSecret", param.getAppSecret());
|
||||
}
|
||||
break;
|
||||
|
||||
case "payment":
|
||||
// 支付配置
|
||||
if (StrUtil.isNotBlank(param.getMchId())) {
|
||||
contentJson.put("mchId", param.getMchId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getApiKey())) {
|
||||
contentJson.put("apiKey", param.getApiKey());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getWechatApiKey())) {
|
||||
contentJson.put("wechatApiKey", param.getWechatApiKey());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getMerchantSerialNumber())) {
|
||||
contentJson.put("merchantSerialNumber", param.getMerchantSerialNumber());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getApiclientCert())) {
|
||||
contentJson.put("apiclientCert", param.getApiclientCert());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getApiclientKey())) {
|
||||
contentJson.put("apiclientKey", param.getApiclientKey());
|
||||
}
|
||||
break;
|
||||
|
||||
case "sms":
|
||||
// 短信配置
|
||||
if (StrUtil.isNotBlank(param.getAccessKeyId())) {
|
||||
contentJson.put("accessKeyId", param.getAccessKeyId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getAccessKeySecret())) {
|
||||
contentJson.put("accessKeySecret", param.getAccessKeySecret());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getSignName())) {
|
||||
contentJson.put("signName", param.getSignName());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getTemplateCode())) {
|
||||
contentJson.put("templateCode", param.getTemplateCode());
|
||||
}
|
||||
break;
|
||||
|
||||
case "wx-work":
|
||||
// 企业微信配置
|
||||
if (StrUtil.isNotBlank(param.getCorpId())) {
|
||||
contentJson.put("corpId", param.getCorpId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getSecret())) {
|
||||
contentJson.put("secret", param.getSecret());
|
||||
}
|
||||
break;
|
||||
|
||||
case "wx-official":
|
||||
// 微信公众号配置
|
||||
if (StrUtil.isNotBlank(param.getAppId())) {
|
||||
contentJson.put("appId", param.getAppId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getAppSecret())) {
|
||||
contentJson.put("appSecret", param.getAppSecret());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getToken())) {
|
||||
contentJson.put("token", param.getToken());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getEncodingAESKey())) {
|
||||
contentJson.put("encodingAESKey", param.getEncodingAESKey());
|
||||
}
|
||||
break;
|
||||
|
||||
case "setting":
|
||||
// 基本设置
|
||||
if (StrUtil.isNotBlank(param.getSiteName())) {
|
||||
contentJson.put("siteName", param.getSiteName());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getLogo())) {
|
||||
contentJson.put("logo", param.getLogo());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getDescription())) {
|
||||
contentJson.put("description", param.getDescription());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getKeywords())) {
|
||||
contentJson.put("keywords", param.getKeywords());
|
||||
}
|
||||
break;
|
||||
|
||||
case "upload":
|
||||
// 上传配置
|
||||
if (StrUtil.isNotBlank(param.getBucketName())) {
|
||||
contentJson.put("bucketName", param.getBucketName());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getBucketDomain())) {
|
||||
contentJson.put("bucketDomain", param.getBucketDomain());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getBucketEndpoint())) {
|
||||
contentJson.put("bucketEndpoint", param.getBucketEndpoint());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getAccessKeyId())) {
|
||||
contentJson.put("accessKeyId", param.getAccessKeyId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getAccessKeySecret())) {
|
||||
contentJson.put("accessKeySecret", param.getAccessKeySecret());
|
||||
}
|
||||
break;
|
||||
|
||||
case "printer":
|
||||
// 打印机配置
|
||||
if (StrUtil.isNotBlank(param.getDeviceNo())) {
|
||||
contentJson.put("deviceNo", param.getDeviceNo());
|
||||
}
|
||||
if (StrUtil.isNotBlank(param.getPrinterKey())) {
|
||||
contentJson.put("printerKey", param.getPrinterKey());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// 处理其他配置或动态字段
|
||||
if (param.getAdditionalProperties() != null) {
|
||||
contentJson.putAll(param.getAdditionalProperties());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
setting.setContent(contentJson.toJSONString());
|
||||
return setting;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,6 +481,7 @@ public class UserController extends BaseController {
|
||||
u.setPoints(one.getPoints());
|
||||
u.setEmail(one.getEmail());
|
||||
u.setAddress(one.getAddress());
|
||||
u.setStatus(one.getStatus());
|
||||
u.setComments(one.getComments());
|
||||
u.setCompanyId(one.getCompanyId());
|
||||
|
||||
@@ -600,6 +601,7 @@ public class UserController extends BaseController {
|
||||
example1.setOrganizationName("总公司");
|
||||
example1.setSexName("男");
|
||||
example1.setRoleName("管理员");
|
||||
example1.setStatus(0);
|
||||
example1.setAddress("地址");
|
||||
example1.setComments("");
|
||||
templateData.add(example1);
|
||||
@@ -615,6 +617,7 @@ public class UserController extends BaseController {
|
||||
example2.setOrganizationName("分公司");
|
||||
example2.setSexName("女");
|
||||
example2.setRoleName("注册用户");
|
||||
example1.setStatus(0);
|
||||
example2.setAddress("地址");
|
||||
example2.setComments("");
|
||||
templateData.add(example2);
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.gxwebsoft.common.core.security.JwtSubject;
|
||||
import com.gxwebsoft.common.core.security.JwtUtil;
|
||||
import com.gxwebsoft.common.core.utils.CommonUtil;
|
||||
import com.gxwebsoft.common.core.utils.RedisUtil;
|
||||
import com.gxwebsoft.common.core.utils.WxMiniProgramDecryptUtil;
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.common.system.entity.*;
|
||||
@@ -112,7 +113,8 @@ public class WxLoginController extends BaseController {
|
||||
throw new BusinessException("授权失败,请重试");
|
||||
}
|
||||
// 查询是否存在
|
||||
User user = userService.getByPhone(phone);
|
||||
|
||||
User user = userService.getAdminByPhone(userParam);
|
||||
// 超级管理员验证
|
||||
if (userParam.getIsSuperAdmin() != null) {
|
||||
final LoginParam loginParam = new LoginParam();
|
||||
@@ -225,45 +227,100 @@ public class WxLoginController extends BaseController {
|
||||
|
||||
// 获取openid
|
||||
private JSONObject getOpenIdByCode(UserParam userParam) {
|
||||
// 获取微信小程序配置信息
|
||||
JSONObject setting = settingService.getBySettingKey("mp-weixin");
|
||||
// 获取openId
|
||||
String apiUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + setting.getString("appId") + "&secret=" + setting.getString("appSecret") + "&js_code=" + userParam.getCode() + "&grant_type=authorization_code";
|
||||
// 执行get请求
|
||||
String result = HttpUtil.get(apiUrl);
|
||||
// 解析access_token
|
||||
return JSON.parseObject(result);
|
||||
try {
|
||||
// 获取微信小程序配置信息
|
||||
JSONObject setting = settingService.getBySettingKey("mp-weixin");
|
||||
// 获取openId
|
||||
String apiUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + setting.getString("appId") + "&secret=" + setting.getString("appSecret") + "&js_code=" + userParam.getCode() + "&grant_type=authorization_code";
|
||||
// 执行get请求
|
||||
String result = HttpUtil.get(apiUrl);
|
||||
|
||||
// 验证响应内容
|
||||
if (StrUtil.isBlank(result)) {
|
||||
throw new BusinessException("微信接口响应为空");
|
||||
}
|
||||
|
||||
// 清理响应中的控制字符
|
||||
String cleanResult = result.trim().replaceAll("[\u0000-\u001f]", "");
|
||||
System.out.println("获取openId响应: " + cleanResult);
|
||||
|
||||
// 解析响应
|
||||
return JSON.parseObject(cleanResult);
|
||||
} catch (Exception e) {
|
||||
System.err.println("获取openId异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
throw new BusinessException("获取openId失败,请重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信手机号码
|
||||
* 支持两种方式:
|
||||
* 1. 新版API方式:使用code直接获取手机号
|
||||
* 2. 旧版解密方式:使用encryptedData、iv、sessionKey解密获取手机号
|
||||
*
|
||||
* @param userParam 需要传微信凭证code
|
||||
* @param userParam 需要传微信凭证code或encryptedData等参数
|
||||
*/
|
||||
private String getPhoneByCode(UserParam userParam) {
|
||||
// 获取手机号码
|
||||
String apiUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken();
|
||||
HashMap<String, Object> paramMap = new HashMap<>();
|
||||
if (StrUtil.isBlank(userParam.getCode())) {
|
||||
throw new BusinessException("code不能为空");
|
||||
// 方式1:如果有encryptedData,使用解密方式获取手机号
|
||||
if (StrUtil.isNotBlank(userParam.getEncryptedData()) &&
|
||||
StrUtil.isNotBlank(userParam.getIv()) &&
|
||||
StrUtil.isNotBlank(userParam.getSessionKey())) {
|
||||
try {
|
||||
return WxMiniProgramDecryptUtil.decryptPhoneNumber(
|
||||
userParam.getEncryptedData(),
|
||||
userParam.getSessionKey(),
|
||||
userParam.getIv()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
System.err.println("解密手机号失败: " + e.getMessage());
|
||||
// 解密失败,继续尝试新版API方式
|
||||
}
|
||||
}
|
||||
paramMap.put("code", userParam.getCode());
|
||||
// 执行post请求
|
||||
String post = HttpUtil.post(apiUrl, JSON.toJSONString(paramMap));
|
||||
JSONObject json = JSON.parseObject(post);
|
||||
if (json.get("errcode").equals(0)) {
|
||||
JSONObject phoneInfo = JSON.parseObject(json.getString("phone_info"));
|
||||
// 微信用户的手机号码
|
||||
final String phoneNumber = phoneInfo.getString("phoneNumber");
|
||||
// 验证手机号码
|
||||
// if (userParam.getNotVerifyPhone() == null && !Validator.isMobile(phoneNumber)) {
|
||||
// String key = ACCESS_TOKEN_KEY.concat(":").concat(getTenantId().toString());
|
||||
// redisTemplate.delete(key);
|
||||
// throw new BusinessException("手机号码格式不正确");
|
||||
// }
|
||||
return phoneNumber;
|
||||
|
||||
// 方式2:使用新版API方式获取手机号
|
||||
if (StrUtil.isNotBlank(userParam.getCode())) {
|
||||
try {
|
||||
String apiUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken();
|
||||
HashMap<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("code", userParam.getCode());
|
||||
// 执行post请求
|
||||
String post = HttpUtil.post(apiUrl, JSON.toJSONString(paramMap));
|
||||
|
||||
// 增加响应内容验证和清理
|
||||
if (StrUtil.isBlank(post)) {
|
||||
throw new BusinessException("微信接口响应为空");
|
||||
}
|
||||
|
||||
// 清理响应中的控制字符
|
||||
String cleanResponse = post.trim().replaceAll("[\u0000-\u001f]", "");
|
||||
System.out.println("微信获取手机号响应: " + cleanResponse);
|
||||
|
||||
JSONObject json = JSON.parseObject(cleanResponse);
|
||||
if (json.get("errcode").equals(0)) {
|
||||
JSONObject phoneInfo = JSON.parseObject(json.getString("phone_info"));
|
||||
// 微信用户的手机号码
|
||||
final String phoneNumber = phoneInfo.getString("phoneNumber");
|
||||
// 验证手机号码
|
||||
// if (userParam.getNotVerifyPhone() == null && !Validator.isMobile(phoneNumber)) {
|
||||
// String key = ACCESS_TOKEN_KEY.concat(":").concat(getTenantId().toString());
|
||||
// redisTemplate.delete(key);
|
||||
// throw new BusinessException("手机号码格式不正确");
|
||||
// }
|
||||
return phoneNumber;
|
||||
} else {
|
||||
String errorMsg = json.getString("errmsg");
|
||||
System.err.println("微信获取手机号失败: errcode=" + json.get("errcode") + ", errmsg=" + errorMsg);
|
||||
throw new BusinessException("获取手机号失败:" + errorMsg);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("获取微信手机号异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
throw new BusinessException("获取手机号失败,请重试");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
throw new BusinessException("获取手机号失败,请检查参数");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,14 +357,32 @@ public class WxLoginController extends BaseController {
|
||||
// 执行get请求
|
||||
String result = HttpUtil.get(url);
|
||||
System.out.println("result = " + result);
|
||||
// 解析access_token
|
||||
JSONObject response = JSON.parseObject(result);
|
||||
if (response.getString("access_token") != null) {
|
||||
// 存入缓存
|
||||
redisTemplate.opsForValue().set(key, result, 7000L, TimeUnit.SECONDS);
|
||||
return response.getString("access_token");
|
||||
|
||||
try {
|
||||
// 验证响应内容
|
||||
if (StrUtil.isBlank(result)) {
|
||||
throw new BusinessException("微信接口响应为空");
|
||||
}
|
||||
|
||||
// 清理响应中的控制字符
|
||||
String cleanResult = result.trim().replaceAll("[\u0000-\u001f]", "");
|
||||
|
||||
// 解析access_token
|
||||
JSONObject response = JSON.parseObject(cleanResult);
|
||||
if (response.getString("access_token") != null) {
|
||||
// 存入缓存
|
||||
redisTemplate.opsForValue().set(key, cleanResult, 7000L, TimeUnit.SECONDS);
|
||||
return response.getString("access_token");
|
||||
} else {
|
||||
String errorMsg = response.getString("errmsg");
|
||||
System.err.println("获取access_token失败: " + errorMsg);
|
||||
throw new BusinessException("获取access_token失败:" + errorMsg);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("解析access_token异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
throw new BusinessException("小程序配置不正确或网络异常");
|
||||
}
|
||||
throw new BusinessException("小程序配置不正确");
|
||||
}
|
||||
|
||||
@ApiOperation("获取微信openId并更新")
|
||||
@@ -450,31 +525,63 @@ public class WxLoginController extends BaseController {
|
||||
}
|
||||
|
||||
// 请求微信接口获取openid
|
||||
String apiUrl = "https://api.weixin.qq.com/sns/jscode2session";
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("appid", AppId);
|
||||
map.put("secret", AppSecret);
|
||||
map.put("js_code", mp.getCode());
|
||||
map.put("grant_type", "authorization_code");
|
||||
final String response = HttpUtil.get(apiUrl, map);
|
||||
final JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
String openid = jsonObject.getString("openid");
|
||||
String sessionKey = jsonObject.getString("session_key");
|
||||
String unionid = jsonObject.getString("unionid");
|
||||
try {
|
||||
String apiUrl = "https://api.weixin.qq.com/sns/jscode2session";
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("appid", AppId);
|
||||
map.put("secret", AppSecret);
|
||||
map.put("js_code", mp.getCode());
|
||||
map.put("grant_type", "authorization_code");
|
||||
final String response = HttpUtil.get(apiUrl, map);
|
||||
|
||||
if (StrUtil.isNotBlank(openid)) {
|
||||
User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getOpenid, openid).last("limit 1"));
|
||||
final User userInfo = userService.getByIdRel(user.getUserId());
|
||||
if (ObjectUtil.isNotEmpty(userInfo)) {
|
||||
// 签发token
|
||||
String access_token = JwtUtil.buildToken(new JwtSubject(user.getUsername(), user.getTenantId()),
|
||||
configProperties.getTokenExpireTime(), configProperties.getTokenKey());
|
||||
loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_REGISTER, null, user.getTenantId(), request);
|
||||
return success("登录成功", new LoginResult(access_token, userInfo));
|
||||
}
|
||||
return fail("用户未注册", openid);
|
||||
// 验证响应内容
|
||||
if (StrUtil.isBlank(response)) {
|
||||
return fail("微信接口响应为空");
|
||||
}
|
||||
|
||||
// 清理响应中的控制字符
|
||||
String cleanResponse = response.trim().replaceAll("[\u0000-\u001f]", "");
|
||||
System.out.println("获取openId响应: " + cleanResponse);
|
||||
|
||||
final JSONObject jsonObject = JSONObject.parseObject(cleanResponse);
|
||||
|
||||
// 检查微信接口是否返回错误
|
||||
if (jsonObject.containsKey("errcode") && !jsonObject.getInteger("errcode").equals(0)) {
|
||||
String errmsg = jsonObject.getString("errmsg");
|
||||
System.err.println("微信接口返回错误: errcode=" + jsonObject.get("errcode") + ", errmsg=" + errmsg);
|
||||
return fail("微信授权失败:" + errmsg);
|
||||
}
|
||||
|
||||
String openid = jsonObject.getString("openid");
|
||||
String sessionKey = jsonObject.getString("session_key");
|
||||
String unionid = jsonObject.getString("unionid");
|
||||
|
||||
if (StrUtil.isNotBlank(openid)) {
|
||||
User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getOpenid, openid).eq(User::getDeleted,0).last("limit 1"));
|
||||
|
||||
// 检查用户是否存在
|
||||
if (user == null) {
|
||||
return fail("用户未注册", openid);
|
||||
}
|
||||
|
||||
final User userInfo = userService.getByIdRel(user.getUserId());
|
||||
if (ObjectUtil.isNotEmpty(userInfo)) {
|
||||
// 签发token
|
||||
String access_token = JwtUtil.buildToken(new JwtSubject(user.getUsername(), user.getTenantId()),
|
||||
configProperties.getTokenExpireTime(), configProperties.getTokenKey());
|
||||
loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_REGISTER, null, user.getTenantId(), request);
|
||||
return success("登录成功", new LoginResult(access_token, userInfo));
|
||||
} else {
|
||||
return fail("用户信息获取失败", openid);
|
||||
}
|
||||
} else {
|
||||
return fail("openId获取失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("openId登录异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return fail("登录失败,请重试");
|
||||
}
|
||||
return fail("openId获取失败");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,6 +48,10 @@ public class Menu implements GrantedAuthority {
|
||||
@ApiModelProperty("菜单类型, 0菜单, 1按钮")
|
||||
private Integer menuType;
|
||||
|
||||
@ApiModelProperty("打开方式, 0当前页, 1新窗口")
|
||||
@TableField(exist = false)
|
||||
private Integer openType;
|
||||
|
||||
@ApiModelProperty("排序号")
|
||||
private Integer sortNumber;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import lombok.Data;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -94,7 +94,7 @@ public class User implements UserDetails {
|
||||
|
||||
@ApiModelProperty("出生日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date birthday;
|
||||
private LocalDateTime birthday;
|
||||
|
||||
@ApiModelProperty(value = "年龄")
|
||||
private Integer age;
|
||||
@@ -235,13 +235,16 @@ public class User implements UserDetails {
|
||||
private String tenantName;
|
||||
|
||||
@ApiModelProperty(value = "最后结算时间")
|
||||
private Date settlementTime;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime settlementTime;
|
||||
|
||||
@ApiModelProperty("注册时间")
|
||||
private Date createTime;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("修改时间")
|
||||
private Date updateTime;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty("公司名称")
|
||||
@TableField(exist = false)
|
||||
|
||||
@@ -57,6 +57,9 @@ public interface UserMapper extends BaseMapper<User> {
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
User selectAdminByPhone(@Param("param") UserParam param);
|
||||
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
User selectAdminByPhone(@Param("param") UserParam param, @Param("tenantId") Integer tenantId);
|
||||
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
User selectByUserId(@Param("userId") Integer userId);
|
||||
|
||||
|
||||
@@ -303,6 +303,9 @@
|
||||
AND a.phone = #{param.phone}
|
||||
AND a.template_id = #{param.templateId}
|
||||
AND (a.username = 'superAdmin' OR a.username = 'admin' OR a.is_admin = 1)
|
||||
<if test="param.tenantId">
|
||||
AND a.tenant_id = #{param.tenantId}
|
||||
</if>
|
||||
LIMIT 1
|
||||
</where>
|
||||
</select>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.gxwebsoft.common.system.param;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.gxwebsoft.common.core.annotation.QueryField;
|
||||
import com.gxwebsoft.common.core.annotation.QueryType;
|
||||
@@ -47,6 +48,10 @@ public class MenuParam extends BaseParam {
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer menuType;
|
||||
|
||||
@ApiModelProperty("打开方式, 0当前页, 1新窗口")
|
||||
@TableField(exist = false)
|
||||
private Integer openType;
|
||||
|
||||
@ApiModelProperty("权限标识")
|
||||
private String authority;
|
||||
|
||||
@@ -72,4 +77,8 @@ public class MenuParam extends BaseParam {
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer companyId;
|
||||
|
||||
@ApiModelProperty("租户名称")
|
||||
@TableField(exist = false)
|
||||
private String tenantName;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.gxwebsoft.common.system.param;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统设置更新参数
|
||||
* 用于处理包含配置字段的更新请求
|
||||
*
|
||||
* @author WebSoft
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@ApiModel(description = "系统设置更新参数")
|
||||
public class SettingUpdateParam {
|
||||
|
||||
@ApiModelProperty(value = "设置项标示")
|
||||
private String settingKey;
|
||||
|
||||
@ApiModelProperty(value = "设置内容(json格式)")
|
||||
private String content;
|
||||
|
||||
@ApiModelProperty(value = "排序号")
|
||||
private Integer sortNumber;
|
||||
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String comments;
|
||||
|
||||
@ApiModelProperty(value = "租户id")
|
||||
private Integer tenantId;
|
||||
|
||||
// 微信小程序配置字段
|
||||
@ApiModelProperty(value = "微信小程序AppId")
|
||||
private String appId;
|
||||
|
||||
@ApiModelProperty(value = "微信小程序AppSecret")
|
||||
private String appSecret;
|
||||
|
||||
// 支付配置字段
|
||||
@ApiModelProperty(value = "商户号")
|
||||
private String mchId;
|
||||
|
||||
@ApiModelProperty(value = "API密钥")
|
||||
private String apiKey;
|
||||
|
||||
@ApiModelProperty(value = "微信支付API密钥")
|
||||
private String wechatApiKey;
|
||||
|
||||
@ApiModelProperty(value = "商户序列号")
|
||||
private String merchantSerialNumber;
|
||||
|
||||
@ApiModelProperty(value = "API客户端证书")
|
||||
private String apiclientCert;
|
||||
|
||||
@ApiModelProperty(value = "API客户端密钥")
|
||||
private String apiclientKey;
|
||||
|
||||
// 短信配置字段
|
||||
@ApiModelProperty(value = "短信AccessKey")
|
||||
private String accessKeyId;
|
||||
|
||||
@ApiModelProperty(value = "短信AccessSecret")
|
||||
private String accessKeySecret;
|
||||
|
||||
@ApiModelProperty(value = "短信签名")
|
||||
private String signName;
|
||||
|
||||
@ApiModelProperty(value = "短信模板")
|
||||
private String templateCode;
|
||||
|
||||
// 企业微信配置字段
|
||||
@ApiModelProperty(value = "企业ID")
|
||||
private String corpId;
|
||||
|
||||
@ApiModelProperty(value = "应用Secret")
|
||||
private String secret;
|
||||
|
||||
// 微信公众号配置字段
|
||||
@ApiModelProperty(value = "公众号Token")
|
||||
private String token;
|
||||
|
||||
@ApiModelProperty(value = "公众号EncodingAESKey")
|
||||
private String encodingAESKey;
|
||||
|
||||
// 基本设置字段
|
||||
@ApiModelProperty(value = "网站名称")
|
||||
private String siteName;
|
||||
|
||||
@ApiModelProperty(value = "网站Logo")
|
||||
private String logo;
|
||||
|
||||
@ApiModelProperty(value = "网站描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "网站关键词")
|
||||
private String keywords;
|
||||
|
||||
// 上传配置字段
|
||||
@ApiModelProperty(value = "存储桶名称")
|
||||
private String bucketName;
|
||||
|
||||
@ApiModelProperty(value = "存储桶域名")
|
||||
private String bucketDomain;
|
||||
|
||||
@ApiModelProperty(value = "存储桶端点")
|
||||
private String bucketEndpoint;
|
||||
|
||||
// 打印机配置字段
|
||||
@ApiModelProperty(value = "打印机设备号")
|
||||
private String deviceNo;
|
||||
|
||||
@ApiModelProperty(value = "打印机密钥")
|
||||
private String printerKey;
|
||||
|
||||
/**
|
||||
* 获取其他未定义的字段
|
||||
* 用于处理动态配置字段
|
||||
*/
|
||||
private Map<String, Object> additionalProperties;
|
||||
}
|
||||
@@ -42,6 +42,9 @@ public class UserImportParam implements Serializable {
|
||||
@Excel(name = "角色")
|
||||
private String roleName;
|
||||
|
||||
@Excel(name = "状态")
|
||||
private Integer status;
|
||||
|
||||
@Excel(name = "备注")
|
||||
private String comments;
|
||||
|
||||
|
||||
@@ -296,4 +296,16 @@ public class UserParam extends BaseParam {
|
||||
@ApiModelProperty(value = "是否已安装")
|
||||
@TableField(exist = false)
|
||||
private Boolean installed;
|
||||
|
||||
@ApiModelProperty(value = "微信小程序解密数据")
|
||||
@TableField(exist = false)
|
||||
private String encryptedData;
|
||||
|
||||
@ApiModelProperty(value = "微信小程序解密向量")
|
||||
@TableField(exist = false)
|
||||
private String iv;
|
||||
|
||||
@ApiModelProperty(value = "微信小程序会话密钥")
|
||||
@TableField(exist = false)
|
||||
private String sessionKey;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,8 @@ public interface UserService extends IService<User>, UserDetailsService {
|
||||
*/
|
||||
User getByPhone(String phone);
|
||||
|
||||
User getByPhone(String phone,Integer tenantId);
|
||||
|
||||
User getByUnionId(UserParam userParam);
|
||||
|
||||
User getByOauthId(UserParam userParam);
|
||||
@@ -114,6 +116,8 @@ public interface UserService extends IService<User>, UserDetailsService {
|
||||
|
||||
User getAdminByPhone(UserParam param);
|
||||
|
||||
User getAdminByPhone(UserParam param,Integer tenantId);
|
||||
|
||||
User getAllByUserId(String userId);
|
||||
|
||||
Integer userNumInPark(UserParam param);
|
||||
|
||||
@@ -181,10 +181,22 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
return getOne(
|
||||
new LambdaQueryWrapper<User>()
|
||||
.eq(User::getPhone, phone)
|
||||
.eq(User::getDeleted,0)
|
||||
.orderByDesc(User::getUserId).last("limit 1")
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByPhone(String phone,Integer tenantId) {
|
||||
return getOne(
|
||||
new LambdaQueryWrapper<User>()
|
||||
.eq(User::getPhone, phone)
|
||||
.eq(User::getTenantId, tenantId)
|
||||
.eq(User::getDeleted,0)
|
||||
.orderByDesc(User::getUserId).last("limit 1")
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByUnionId(UserParam param) {
|
||||
return getOne(
|
||||
@@ -276,10 +288,13 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
|
||||
@Override
|
||||
public User getAdminByPhone(UserParam param) {
|
||||
System.out.println("param222 = " + param);
|
||||
return baseMapper.selectAdminByPhone(param);
|
||||
}
|
||||
|
||||
public User getAdminByPhone(UserParam param,Integer tenantId){
|
||||
return baseMapper.selectAdminByPhone(param,tenantId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<User> getAdminsByPhone(LoginParam param){
|
||||
final UserParam userParam = new UserParam();
|
||||
|
||||
Reference in New Issue
Block a user