ソースを参照

微信小程序登录

gqx 2 年 前
コミット
4cce7f0284

+ 6 - 1
jeecg-boot-base-core/pom.xml

@@ -209,6 +209,11 @@
 			<groupId>com.fasterxml.jackson.module</groupId>
 			<artifactId>jackson-module-kotlin</artifactId>
 		</dependency>
+		<!--TTL-->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>transmittable-thread-local</artifactId>
+		</dependency>
 	</dependencies>
 
-</project>
+</project>

+ 21 - 19
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java

@@ -30,7 +30,7 @@ public interface CommonConstant {
 	 * 系统日志类型: 登录
 	 */
 	int LOG_TYPE_1 = 1;
-	
+
 	/**
 	 * 系统日志类型: 操作
 	 */
@@ -40,38 +40,38 @@ public interface CommonConstant {
 	 * 操作日志类型: 查询
 	 */
 	int OPERATE_TYPE_1 = 1;
-	
+
 	/**
 	 * 操作日志类型: 添加
 	 */
 	int OPERATE_TYPE_2 = 2;
-	
+
 	/**
 	 * 操作日志类型: 更新
 	 */
 	int OPERATE_TYPE_3 = 3;
-	
+
 	/**
 	 * 操作日志类型: 删除
 	 */
 	int OPERATE_TYPE_4 = 4;
-	
+
 	/**
 	 * 操作日志类型: 倒入
 	 */
 	int OPERATE_TYPE_5 = 5;
-	
+
 	/**
 	 * 操作日志类型: 导出
 	 */
 	int OPERATE_TYPE_6 = 6;
-	
-	
+
+
 	/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
     Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
     /** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
     Integer SC_OK_200 = 200;
-    
+
     /**访问权限认证未通过 510*/
     Integer SC_JEECG_NO_AUTHZ=510;
 
@@ -82,6 +82,8 @@ public interface CommonConstant {
 //    /** Token缓存时间:3600秒即一小时 */
 //    int  TOKEN_EXPIRE_TIME  = 3600;
 
+    /** 登录用户Token令牌缓存KEY前缀 */
+    String PREFIX_WX_APP_USER_TOKEN  = "prefix_wx_app_user_token:";
     /** 登录二维码 */
     String  LOGIN_QRCODE_PRE  = "QRCODELOGIN:";
     String  LOGIN_QRCODE  = "LQ:";
@@ -94,7 +96,7 @@ public interface CommonConstant {
      */
     Integer MENU_TYPE_0  = 0;
    /**
-    *  1:子菜单 
+    *  1:子菜单
     */
     Integer MENU_TYPE_1  = 1;
     /**
@@ -105,34 +107,34 @@ public interface CommonConstant {
     /**通告对象类型(USER:指定用户,ALL:全体用户)*/
     String MSG_TYPE_UESR  = "USER";
     String MSG_TYPE_ALL  = "ALL";
-    
+
     /**发布状态(0未发布,1已发布,2已撤销)*/
     String NO_SEND  = "0";
     String HAS_SEND  = "1";
     String HAS_CANCLE  = "2";
-    
+
     /**阅读状态(0未读,1已读)*/
     String HAS_READ_FLAG  = "1";
     String NO_READ_FLAG  = "0";
-    
+
     /**优先级(L低,M中,H高)*/
     String PRIORITY_L  = "L";
     String PRIORITY_M  = "M";
     String PRIORITY_H  = "H";
-    
+
     /**
      * 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
      */
     String SMS_TPL_TYPE_0  = "0";
     String SMS_TPL_TYPE_1  = "1";
     String SMS_TPL_TYPE_2  = "2";
-    
+
     /**
      * 状态(0无效1有效)
      */
     String STATUS_0 = "0";
     String STATUS_1 = "1";
-    
+
     /**
      * 同步工作流引擎1同步0不同步
      */
@@ -144,7 +146,7 @@ public interface CommonConstant {
      */
     String MSG_CATEGORY_1 = "1";
     String MSG_CATEGORY_2 = "2";
-    
+
     /**
      * 是否配置菜单的数据权限 1是0否
      */
@@ -156,7 +158,7 @@ public interface CommonConstant {
      */
     Integer USER_UNFREEZE = 1;
     Integer USER_FREEZE = 2;
-    
+
     /**字典翻译文本后缀*/
     String DICT_TEXT_SUFFIX = "_dictText";
 
@@ -381,7 +383,7 @@ public interface CommonConstant {
      * https:// https协议
      */
     String HTTPS_PROTOCOL = "https://";
-    
+
     /** 部门表唯一key,id */
     String DEPART_KEY_ID = "id";
     /** 部门表唯一key,orgCode */

+ 36 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TenantContextHolder.java

@@ -0,0 +1,36 @@
+package org.jeecg.common.util;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 租户工具类
+ */
+@UtilityClass
+public class TenantContextHolder {
+    private final ThreadLocal<String> THREAD_LOCAL_TENANT = new TransmittableThreadLocal<>();
+
+
+    /**
+     * TTL 设置租户ID
+     *
+     * @param tenantId
+     */
+    public void setTenantId(String tenantId) {
+        THREAD_LOCAL_TENANT.set(tenantId);
+    }
+
+    /**
+     * 获取TTL中的租户ID
+     *
+     * @return
+     */
+    public String getTenantId() {
+        return THREAD_LOCAL_TENANT.get();
+    }
+
+    public void clear() {
+        THREAD_LOCAL_TENANT.remove();
+    }
+}

+ 20 - 0
jeecg-mall-api/pom.xml

@@ -16,6 +16,26 @@
             <groupId>org.jeecgframework.boot</groupId>
             <artifactId>jeecg-boot-base-core</artifactId>
         </dependency>
+        <!--weixin-java-common-->
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-common</artifactId>
+        </dependency>
+        <!--weixin-java-miniapp-->
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-miniapp</artifactId>
+        </dependency>
+        <!--weixin-java-mp-->
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-mp</artifactId>
+        </dependency>
+        <!--weixin-java-open-->
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-open</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 47 - 0
jeecg-mall-api/src/main/java/com/util/ThirdSessionHolder.java

@@ -0,0 +1,47 @@
+package com.util;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import lombok.experimental.UtilityClass;
+import org.jeecg.modules.wxuser.entity.ThirdSession;
+
+/**
+ * sessionToken工具类
+ */
+@UtilityClass
+public class ThirdSessionHolder {
+
+	private final ThreadLocal<ThirdSession> THREAD_LOCAL_THIRD_SESSION = new TransmittableThreadLocal<>();
+
+	/**
+	 * TTL 设置thirdSession
+	 *
+	 * @param thirdSession
+	 */
+	public void setThirdSession(ThirdSession thirdSession) {
+		THREAD_LOCAL_THIRD_SESSION.set(thirdSession);
+	}
+
+	/**
+	 * 获取TTL中的thirdSession
+	 *
+	 * @return
+	 */
+	public ThirdSession getThirdSession() {
+		ThirdSession thirdSession = THREAD_LOCAL_THIRD_SESSION.get();
+		return thirdSession;
+	}
+
+	/**
+	 * 获取用户商城ID
+	 * @return
+	 */
+	public String getUserId(){
+		if(getThirdSession() != null){
+			return getThirdSession().getUserId();
+		}
+		return null;
+	}
+	public void clear() {
+		THREAD_LOCAL_THIRD_SESSION.remove();
+	}
+}

+ 34 - 4
jeecg-mall-api/src/main/java/org/jeecg/modules/wxuser/controller/WxUserController.java

@@ -1,24 +1,33 @@
 package org.jeecg.modules.wxuser.controller;
 
+import cn.binarywang.wx.miniapp.api.WxMaUserService;
+import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.util.ThirdSessionHolder;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.query.MatchTypeEnum;
 import org.jeecg.common.system.query.QueryCondition;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.constant.VxeSocketConst;
 import org.jeecg.modules.wxuser.dto.LoginDto;
+import org.jeecg.modules.wxuser.dto.WxOpenDataDto;
+import org.jeecg.modules.wxuser.entity.ThirdSession;
+import org.jeecg.modules.wxuser.entity.UserInfo;
+import org.jeecg.modules.wxuser.service.IUserInfoService;
 import org.springframework.web.bind.annotation.*;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.io.InputStream;
@@ -34,6 +43,8 @@ import java.util.*;
 @RequestMapping("/mall-api/wxuser")
 public class WxUserController {
 
+    @Resource
+    private IUserInfoService userInfoService;
     /**
      * 小程序用户登录
      * @param request
@@ -41,15 +52,34 @@ public class WxUserController {
      * @return
      */
     @ApiOperation(value = "小程序用户登录")
-    @PostMapping("/loginma")
-    public Result<JSONObject> loginMa(HttpServletRequest request, @RequestBody LoginDto dto){
+    @PostMapping("/ma-login")
+    public Result<UserInfo> loginMa(HttpServletRequest request, @RequestBody LoginDto dto) {
         try {
             String appId = request.getHeader("app-id");
-            if(StringUtils.isBlank(appId)){
+            if (StringUtils.isBlank(appId)) {
                 return Result.error("缺少appid");
             }
             dto.setAppId(appId);
-            return Result.ok();
+            UserInfo userInfo = userInfoService.loginMa(dto);
+            return Result.ok(userInfo);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return Result.error(e.getMessage());
+        }
+    }
+
+    /**
+     * 通过小程序授权手机号一键登录商城
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "通过小程序授权手机号一键登录商城")
+    @PostMapping("/ma-phone-login")
+    public Result loginByPhoneMa(HttpServletRequest request, @RequestBody WxOpenDataDto dto) {
+        try {
+            String token = request.getHeader("third-session");
+            UserInfo userInfo = userInfoService.loginByPhoneMa(dto, token);
+            return Result.ok(userInfo);
         } catch (Exception e) {
             e.printStackTrace();
             return Result.error(e.getMessage());

+ 21 - 0
jeecg-mall-api/src/main/java/org/jeecg/modules/wxuser/dto/WxOpenDataDto.java

@@ -0,0 +1,21 @@
+package org.jeecg.modules.wxuser.dto;
+
+import lombok.Data;
+
+/**
+ * 微信开发数据
+ */
+@Data
+public class WxOpenDataDto {
+    private String appId;
+    private String userId;
+    private String encryptedData;
+    private String errMsg;
+    private String iv;
+    private String rawData;
+    private String signature;
+    private String sessionKey;
+    private String mallUserId;
+    private String jsCode;
+    private String spread;
+}

+ 33 - 0
jeecg-mall-api/src/main/java/org/jeecg/modules/wxuser/entity/ThirdSession.java

@@ -0,0 +1,33 @@
+package org.jeecg.modules.wxuser.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class ThirdSession implements Serializable {
+    /**
+     * 所属租户
+     */
+    private String tenantId;
+    /**
+     * 微信用户ID
+     */
+    private String wxUserId;
+    /**
+     * 配置项ID
+     */
+    private String appId;
+    /**
+     * 微信sessionKey
+     */
+    private String sessionKey;
+    /**
+     * 用户标识
+     */
+    private String openId;
+    /**
+     * 商城用户ID
+     */
+    private String userId;
+}

+ 5 - 4
jeecg-mall-api/src/main/java/org/jeecg/modules/wxuser/entity/UserInfo.java

@@ -4,10 +4,8 @@ import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.util.Date;
 import java.math.BigDecimal;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.annotation.TableLogic;
+
+import com.baomidou.mybatisplus.annotation.*;
 import lombok.Data;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import org.springframework.format.annotation.DateTimeFormat;
@@ -90,4 +88,7 @@ public class UserInfo implements Serializable {
     @DateTimeFormat(pattern="yyyy-MM-dd")
     @ApiModelProperty(value = "更新时间")
     private Date updateTime;
+
+    @TableField(exist = false)
+    private String token;
 }

+ 3 - 3
jeecg-mall-api/src/main/java/org/jeecg/modules/wxuser/entity/WxUser.java

@@ -61,9 +61,9 @@ public class WxUser implements Serializable {
     @ApiModelProperty(value = "unionid")
     private String unionId;
 	/**关联用户表*/
-	@Excel(name = "关联用户表", width = 15)
-    @ApiModelProperty(value = "关联用户表")
-    private Integer userId;
+	@Excel(name = "关联用户表id", width = 15)
+    @ApiModelProperty(value = "关联用户表id")
+    private String userId;
 	/**头像*/
 	@Excel(name = "头像", width = 15)
     @ApiModelProperty(value = "头像")

+ 15 - 0
jeecg-mall-api/src/main/java/org/jeecg/modules/wxuser/service/IUserInfoService.java

@@ -1,7 +1,10 @@
 package org.jeecg.modules.wxuser.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.wxuser.dto.LoginDto;
+import org.jeecg.modules.wxuser.dto.WxOpenDataDto;
 import org.jeecg.modules.wxuser.entity.UserInfo;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * @Description: user_info
@@ -10,5 +13,17 @@ import org.jeecg.modules.wxuser.entity.UserInfo;
  * @Version: V1.0
  */
 public interface IUserInfoService extends IService<UserInfo> {
+    /**
+     * wx.login登陆成功之后发送请求,后端登录
+     * @param dto
+     * @return
+     */
+    public UserInfo loginMa(LoginDto dto);
 
+    /**
+     * 通过小程序授权手机号一键登录商城
+     * @param dto
+     * @return
+     */
+    public UserInfo loginByPhoneMa(WxOpenDataDto dto, String token);
 }

+ 204 - 0
jeecg-mall-api/src/main/java/org/jeecg/modules/wxuser/service/impl/UserInfoServiceImpl.java

@@ -1,14 +1,44 @@
 package org.jeecg.modules.wxuser.service.impl;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.api.WxMaUserService;
+import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
+import cn.hutool.core.date.DateTime;
 import cn.hutool.core.util.StrUtil;
+import com.alibaba.druid.support.json.JSONUtils;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.util.ThirdSessionHolder;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.exception.JeecgBootException;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.common.util.TenantContextHolder;
 import org.jeecg.modules.wxuser.dto.LoginDto;
+import org.jeecg.modules.wxuser.dto.WxOpenDataDto;
+import org.jeecg.modules.wxuser.entity.ThirdSession;
 import org.jeecg.modules.wxuser.entity.UserInfo;
+import org.jeecg.modules.wxuser.entity.WxAppConfig;
+import org.jeecg.modules.wxuser.entity.WxUser;
 import org.jeecg.modules.wxuser.mapper.UserInfoMapper;
 import org.jeecg.modules.wxuser.service.IUserInfoService;
+import org.jeecg.modules.wxuser.service.IWxAppConfigService;
+import org.jeecg.modules.wxuser.service.IWxUserService;
+import org.jeecg.modules.wxuser.weixin.config.ma.WxMaInRedisConfigStorage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Date;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
@@ -20,5 +50,179 @@ import java.util.concurrent.TimeUnit;
  */
 @Service
 public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements IUserInfoService {
+@Resource
+private IWxAppConfigService wxAppConfigService;
+    @Resource
+    private  RedisTemplate redisTemplate;
+    @Autowired
+    private RedisUtil redisUtil;
+    @Resource
+    private IWxUserService wxUserService;
 
+    /**
+     * wx.login登陆成功之后发送请求,后端登录
+     * @param dto
+     * @return
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public UserInfo loginMa(LoginDto dto) {
+        LambdaQueryWrapper<WxAppConfig> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(WxAppConfig::getAppId, dto.getAppId());
+        WxAppConfig wxApp = wxAppConfigService.getOne(lambdaQueryWrapper);
+        if (wxApp == null) {
+            throw new JeecgBootException("没有找到此appid");
+        }
+        TenantContextHolder.setTenantId(wxApp.getTenantId());
+        WxUser wxUser = null;
+        //通过code获取微信用户信息
+        try {
+            WxMaInRedisConfigStorage configStorage = new WxMaInRedisConfigStorage(redisTemplate);
+            configStorage.setAppid(wxApp.getId());
+            configStorage.setSecret(wxApp.getAppSecret());
+            WxMaService wxMaService = new WxMaServiceImpl();
+            wxMaService.setWxMaConfig(configStorage);
+
+            WxMaJscode2SessionResult jscode2session = wxMaService.jsCode2SessionInfo(dto.getJsCode());
+            String openId = jscode2session.getOpenid();
+            LambdaQueryWrapper<WxUser> lambdaQueryWrapper2 = new LambdaQueryWrapper<>();
+            lambdaQueryWrapper2.eq(WxUser::getAppId, wxApp.getAppId());
+            lambdaQueryWrapper2.eq(WxUser::getOpenId, openId);
+            wxUser = wxUserService.getOne(lambdaQueryWrapper2);
+            if (wxUser == null) {
+                wxUser = new WxUser();
+                wxUser.setOpenId(openId);
+            }
+            wxUser.setSessionKey(jscode2session.getSessionKey());
+            wxUser.setUnionId(jscode2session.getUnionid());
+        } catch (WxErrorException e) {
+            e.printStackTrace();
+            throw new JeecgBootException("小程序获取登录后的微信用户失败:" + e.getMessage());
+        }
+        System.out.println("【授权登录前】" + wxUser.toString());
+        UserInfo userInfo;
+        if (wxUser == null || StrUtil.isBlank(wxUser.getId())) {
+            //新增微信用户
+            wxUser.setAppId(wxApp.getId());
+            wxUser.setAppType(wxApp.getAppType());
+            wxUserService.saveOrUpdate(wxUser);
+        }
+        System.out.println("【授权登录后】" + wxUser.toString());
+        if (StrUtil.isNotBlank(wxUser.getUserId())) {
+            userInfo = baseMapper.selectById(wxUser.getUserId());
+        } else {
+            userInfo = new UserInfo();
+        }
+        System.out.println("【用户信息】" + userInfo.toString());
+
+        String token = UUID.randomUUID().toString();
+        ThirdSession thirdSession = new ThirdSession();
+        thirdSession.setTenantId(wxApp.getTenantId());
+        thirdSession.setAppId(wxApp.getId());
+        thirdSession.setSessionKey(wxUser.getSessionKey());
+        thirdSession.setWxUserId(wxUser.getId());
+        thirdSession.setOpenId(wxUser.getOpenId());
+        thirdSession.setUserId(wxUser.getUserId());
+
+        String key = CommonConstant.PREFIX_WX_APP_USER_TOKEN + token;
+
+        // 设置token缓存有效时间
+        redisUtil.set(key, JSONUtils.toJSONString(thirdSession));
+        redisUtil.expire(key, JwtUtil.EXPIRE_TIME * 24 * 30 / 1000);
+        userInfo.setToken(token);
+        return userInfo;
+    }
+
+    /**
+     * 通过小程序授权手机号一键登录商城
+     * @param dto
+     * @return
+     */
+    public UserInfo loginByPhoneMa(WxOpenDataDto dto,String token) {
+        ThirdSession thirdSession = ThirdSessionHolder.getThirdSession();
+        String key = CommonConstant.PREFIX_WX_APP_USER_TOKEN + token;
+        dto.setSessionKey(thirdSession.getSessionKey());
+        //解密获取手机号
+        LambdaQueryWrapper<WxAppConfig> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(WxAppConfig::getAppId, dto.getAppId());
+        WxAppConfig wxApp = wxAppConfigService.getOne(lambdaQueryWrapper);
+        if (wxApp == null) {
+            throw new JeecgBootException("没有找到此appid");
+        }
+        String phone = "";
+        try {
+            WxMaInRedisConfigStorage configStorage = new WxMaInRedisConfigStorage(redisTemplate);
+            configStorage.setAppid(wxApp.getId());
+            configStorage.setSecret(wxApp.getAppSecret());
+            WxMaService wxMaService = new WxMaServiceImpl();
+            wxMaService.setWxMaConfig(configStorage);
+
+            WxMaUserService wxMaUserService = wxMaService.getUserService();
+            WxMaPhoneNumberInfo wxMaPhoneNumberInfo = wxMaUserService.getPhoneNoInfo(dto.getSessionKey(), dto.getEncryptedData(), dto.getIv());
+            phone = wxMaPhoneNumberInfo.getPhoneNumber();
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new JeecgBootException("微信小程序授权拉取手机号码:" + e.getMessage());
+        }
+        //通过手机号登录
+        UserInfo userInfo = loginByMobileWx(thirdSession, phone, key);
+        return userInfo;
+    }
+
+
+    @Transactional(rollbackFor = Exception.class)
+    public UserInfo loginByMobileWx(ThirdSession thirdSession, String mobile, String key) {
+        //先查询该手机号是不是商城用户
+        UserInfo userInfo = baseMapper.selectOne(Wrappers.<UserInfo>lambdaQuery()
+                .eq(UserInfo::getMobile, mobile));
+        if (userInfo == null) {//不是商城用户,则新增
+            userInfo = new UserInfo();
+            userInfo.setCreateTime(DateTime.now());
+            userInfo.setUpdateTime(DateTime.now());
+        }
+        //先获取微信用户信息
+        WxUser wxUser = wxUserService.getById(thirdSession.getWxUserId());
+        //新增商城用户
+        if (ObjectUtils.isEmpty(userInfo.getAppType())) {
+            userInfo.setAppType(1);
+        }
+        if (StrUtil.isBlank(userInfo.getAppId())) {
+            userInfo.setAppId(wxUser.getAppId());
+        }
+        if (StrUtil.isBlank(userInfo.getMobile())) {
+            userInfo.setMobile(mobile);
+        }
+        if (StrUtil.isBlank(userInfo.getNickName())) {
+            userInfo.setNickName(wxUser.getNickName());
+        }
+        if (StrUtil.isBlank(userInfo.getCity())) {
+            userInfo.setCity(wxUser.getCity());
+        }
+        if (StrUtil.isBlank(userInfo.getCountry())) {
+            userInfo.setCountry(wxUser.getCountry());
+        }
+        if (StrUtil.isBlank(userInfo.getAvatar())) {
+            userInfo.setAvatar(wxUser.getAvatar());
+        }
+        if (StrUtil.isBlank(userInfo.getProvince())) {
+            userInfo.setProvince(wxUser.getProvince());
+        }
+        if (ObjectUtils.isEmpty(userInfo.getGender())) {
+            userInfo.setGender(wxUser.getGender());
+        }
+        //更新或新增商城用户
+        this.saveOrUpdate(userInfo);
+        String mallUserId = userInfo.getId();
+        wxUser.setUserId(mallUserId);
+        wxUser.setMobile(mobile);
+
+        userInfo.setToken(StrUtil.removeAll(key, CommonConstant.PREFIX_WX_APP_USER_TOKEN));
+        //更新微信用户
+
+        //更新redis中的thirdSession
+        thirdSession.setUserId(mallUserId);
+        // 设置token缓存有效时间
+        redisUtil.set(key, JSONUtils.toJSONString(thirdSession));
+        redisUtil.expire(key, JwtUtil.EXPIRE_TIME * 24 * 30 / 1000);
+        return userInfo;
+    }
 }

+ 100 - 0
jeecg-mall-api/src/main/java/org/jeecg/modules/wxuser/weixin/config/ma/WxMaInRedisConfigStorage.java

@@ -0,0 +1,100 @@
+
+package org.jeecg.modules.wxuser.weixin.config.ma;
+
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基于Redis的微信配置provider.
+ *
+ * @author jl
+ */
+@SuppressWarnings("serial")
+public class WxMaInRedisConfigStorage extends WxMaDefaultConfigImpl {
+
+	public static final String ACCESS_TOKEN_KEY = "wx:ma:access_token:";
+
+	public final static String JSAPI_TICKET_KEY = "wx:ma:jsapi_ticket:";
+
+	public final static String CARDAPI_TICKET_KEY = "wx:ma:cardapi_ticket:";
+
+	private final RedisTemplate<String, String> redisTemplate;
+
+	public WxMaInRedisConfigStorage(RedisTemplate redisTemplate) {
+		this.redisTemplate = redisTemplate;
+	}
+
+	private String accessTokenKey;
+
+	private String jsapiTicketKey;
+
+	private String cardapiTicketKey;
+
+	/**
+	 * 每个小程序生成独有的存储key.
+	 */
+	@Override
+	public void setAppid(String appId) {
+		super.setAppid(appId);
+		this.accessTokenKey = ACCESS_TOKEN_KEY.concat(appId);
+		this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(appId);
+		this.cardapiTicketKey = CARDAPI_TICKET_KEY.concat(appId);
+	}
+
+
+	/**
+	 *
+	 * @return
+	 */
+	@Override
+	public String getAccessToken() {
+		return redisTemplate.opsForValue().get(this.accessTokenKey);
+	}
+
+	/**
+	 *
+	 * @return
+	 */
+	@Override
+	public boolean isAccessTokenExpired() {
+		return redisTemplate.getExpire(accessTokenKey) < 2;
+	}
+
+	/**
+	 *
+	 * @param accessToken
+	 * @param expiresInSeconds
+	 */
+	@Override
+	public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
+		redisTemplate.opsForValue().set(this.accessTokenKey, accessToken, expiresInSeconds - 200, TimeUnit.SECONDS);
+	}
+
+	/**
+	 *
+	 */
+	@Override
+	public void expireAccessToken() {
+		redisTemplate.expire(this.accessTokenKey, 0, TimeUnit.SECONDS);
+	}
+
+	/**
+	 *
+	 * @return
+	 */
+	@Override
+	public String getJsapiTicket() {
+		return redisTemplate.opsForValue().get(this.jsapiTicketKey);
+	}
+
+	/**
+	 *
+	 * @return
+	 */
+	@Override
+	public String getCardApiTicket() {
+		return redisTemplate.opsForValue().get(cardapiTicketKey);
+	}
+}

+ 32 - 0
pom.xml

@@ -59,6 +59,8 @@
 		<!-- Log4j2爆雷漏洞 -->
 		<log4j2.version>2.17.0</log4j2.version>
 		<logback.version>1.2.9</logback.version>
+		<ttl.version>2.11.4</ttl.version>
+		<weixin-java.version>4.0.0</weixin-java.version>
 	</properties>
 
 	<modules>
@@ -331,6 +333,36 @@
 				<artifactId>jimureport-nosql-starter</artifactId>
 				<version>${jimureport-spring-boot-starter.version}</version>
 			</dependency>
+			<!--TTL-->
+			<dependency>
+				<groupId>com.alibaba</groupId>
+				<artifactId>transmittable-thread-local</artifactId>
+				<version>${ttl.version}</version>
+			</dependency>
+			<!--weixin-java-common-->
+			<dependency>
+				<groupId>com.github.binarywang</groupId>
+				<artifactId>weixin-java-common</artifactId>
+				<version>${weixin-java.version}</version>
+			</dependency>
+			<!--weixin-java-admin-->
+			<dependency>
+				<groupId>com.github.binarywang</groupId>
+				<artifactId>weixin-java-mp</artifactId>
+				<version>${weixin-java.version}</version>
+			</dependency>
+			<!--weixin-java-open-->
+			<dependency>
+				<groupId>com.github.binarywang</groupId>
+				<artifactId>weixin-java-open</artifactId>
+				<version>${weixin-java.version}</version>
+			</dependency>
+			<!--weixin-java-miniapp-->
+			<dependency>
+				<groupId>com.github.binarywang</groupId>
+				<artifactId>weixin-java-miniapp</artifactId>
+				<version>${weixin-java.version}</version>
+			</dependency>
 		</dependencies>
 	</dependencyManagement>