# weixin-java-miniapp 小程序登录

# 引入依赖:

<dependency>
   <groupId>com.github.binarywang</groupId>
   <artifactId>weixin-java-miniapp</artifactId>
   <version>4.6.0</version>
</dependency>

# 在 application.yml 配置小程序登录信息

wxmini:
  appid: wx640242aed1878581
  secret: 9a8b5c2e0d07d79f13cae8a2b5c61e15
  msgDataFormat: JSON
tokensecret: oiasj123j23

# 创建 Config

目标:

  • 配置 appid
  • 配置 secret
  • 配置 msgDataFormat
  • 配置其它信息
package org.dromara.dkxmodules.xcx.config;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConditionalOnClass(WxMaService.class)
public class WxConfig
{
    @Value(value = "${wxmini.appid}")
    private String appid;
    @Value(value = "${wxmini.secret}")
    private String secret;
    // @Value(value = "")
    private String token;
    // @Value(value = "")
    private String aesKey;
    @Value(value = "${wxmini.msgDataFormat}")
    private String msgDataFormat;
    @Bean
    @ConditionalOnMissingBean(WxMaService.class)
    public WxMaService getWxMaService()
    {
        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid(appid);
        config.setSecret(secret);
        config.setMsgDataFormat(msgDataFormat);
        WxMaServiceImpl wxMaService = new WxMaServiceImpl();
        wxMaService.setWxMaConfig(config);
        return wxMaService;
    }
}

# 创建实体类和参数类

UserEntity

@Data
@TableName("tab_user")
@Builder
public class UserEntity implements Serializable {
	private static final long serialVersionUID = 1L;
	/**
	 * 用户 id
	 */
	@TableId
	private Long id;
	/**
	 * 用户名
	 */
	private String nickname;
	/**
	 * 用户性别
	 */
	private String sex;
	/**
	 * 用户头像
	 */
	private String head;
	/**
	 * 用户生日
	 */
	private String birthday;
	/**
	 * 微信登录标识 id
	 */
	private String openId;
	/**
	 * 微信号码
	 */
	private String wxUnionId;
	/**
	 * 手机号码
	 */
	private String phone;
	/**
	 * 用户状态 (0: 启用,1: 未启用)
	 */
	private String state;
	/**
	 * 用户地区
	 */
	private String address;
	/**
	 * 用户创建时间
	 */
	private Date createTime;
	/**
	 * 用户删除时间
	 */
	private Date deleteTime;
	/**
	 * 逻辑删除
	 */
    @TableLogic
	private Integer isDel;
}

UserInfo

import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigInteger;
@Data
@NoArgsConstructor
public class UserInfo
{
    private BigInteger id;
    /**
     * 用户名
     */
    private String nickname;
    /**
     * 用户性别
     */
    private String gender;
    /**
     * 用户头像
     */
    private String avatarUrl;
    /**
     * 用户生日
     */
    private String birthday;
    /**
     * 微信登录标识 id
     */
    private String openId;
    /**
     * 微信号码
     */
    private String wxUnionId;
    /**
     * 手机号码
     */
    private String phone;
    /**
     * 市
     */
    private String city;
    /**
     * 国家
     */
    private String country;
    /**
     * 语言
     */
    private String language;
    /**
     * 省
     */
    private String province;
}

Params

@Data
@NoArgsConstructor
public class Params
{
    private String encryptedData;
    private String iv;
    private String sessionId;
    private String appId;
}

# 创建 Mapper 层

@Mapper
public interface XcxUserMapper extends BaseMapper<UserEntity>
{
}

# 创建 Service 和实现类层

service

import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.core.domain.R;
import org.dromara.dkxmodules.xcx.entity.UserEntity;
public interface WxLoginService extends IService<UserEntity>
{
    R authLogin(WxMaUserInfo wxMaUserInfo, String phoneNumber, String sessionKey);
}

serviceimpl

import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.dkxmodules.xcx.entity.UserEntity;
import org.dromara.dkxmodules.xcx.entity.UserInfo;
import org.dromara.dkxmodules.xcx.mapper.XcxUserMapper;
import org.dromara.dkxmodules.xcx.service.WxLoginService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Service(value = "wxLoginService")
@RequiredArgsConstructor
public class WxLoginServiceImpl extends ServiceImpl<XcxUserMapper, UserEntity> implements WxLoginService
{
    @Value(value = "${tokensecret}")
    private String tokenSecret;
    @NonNull
    private StringRedisTemplate redisTemplate;
    @Override
    public R authLogin(WxMaUserInfo wxMaUserInfo, String phoneNumber, String sessionKey)
    {
        UserInfo userInfo = new UserInfo();
        BeanUtil.copyProperties(wxMaUserInfo, userInfo);
        userInfo.setPhone(phoneNumber);
        String s = redisTemplate.opsForValue().get("xcxLogin" + sessionKey);
        JSONObject jsonObject = JSON.parseObject(s);
        String openId = (String) jsonObject.get("openId");
        UserEntity userEntity = baseMapper.selectOne(Wrappers.<UserEntity>lambdaQuery()
            .eq(UserEntity::getOpenId, openId));
        if (userEntity == null)
        {
            return getRegister(userInfo);
        }
        else
        {
            return getLogin(userInfo);
        }
    }
    private R getLogin(UserInfo userInfo)
    {
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", userInfo.getId());
        map.put("nickname", userInfo.getNickname());
        map.put("phone", userInfo.getPhone());
        String token = JWTUtil.createToken(map, tokenSecret.getBytes());
        map.put("token", token);
        UUID uuid = UUID.randomUUID();
        redisTemplate.opsForValue().set("token_" + uuid, JSON.toJSONString(map), 7, TimeUnit.DAYS);
        return R.ok("token: " + token);
    }
    private R getRegister(UserInfo userInfo)
    {
        UserEntity userEntity = UserEntity.builder()
            .nickname(userInfo.getNickname())
            .sex(userInfo.getGender())
            .openId(userInfo.getOpenId())
            .head(userInfo.getAvatarUrl())
            .phone(userInfo.getPhone())
            .address(/*userInfo.getCountry() + "/" + userInfo.getProvince() + "/" +*/ userInfo.getCity())
            .build();
        this.baseMapper.insert(userEntity);
        userInfo.setId(BigInteger.valueOf(userEntity.getId()));
        return this.getLogin(userInfo);
    }
}

# 创建 controller 层

import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import io.netty.util.internal.StringUtil;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import org.dromara.common.core.domain.R;
import org.dromara.dkxmodules.xcx.config.WxConfig;
import org.dromara.dkxmodules.xcx.entity.dto.Params;
import org.dromara.dkxmodules.xcx.service.WxLoginService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import shade.powerjob.com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/wxLoginController")
@AllArgsConstructor
public class WxLoginController
{
    private WxLoginService wxLoginService;
    private WxConfig wxConfig;
    private StringRedisTemplate redisTemplate;
    @GetMapping("/wxLogin")
    public Object wxLogin(String code)
    {
        HashMap<String, Object> map = new HashMap<>();
        String sessionKey = null;
        String openid = null;
        try
        {
            // 通过 code 获取 openid 和 sessionkey
            WxMaJscode2SessionResult sessionInfo = wxConfig.getWxMaService().getUserService().getSessionInfo(code);
            openid = sessionInfo.getOpenid();
            sessionKey = sessionInfo.getSessionKey();
        } catch (WxErrorException e)
        {
            throw new RuntimeException(e);
        }
        if (StringUtil.isNullOrEmpty(sessionKey) || StringUtil.isNullOrEmpty(openid))
        {
            return R.fail();
        }
        map.put("openId", openid);
        map.put("sessionKey", sessionKey);
        String toOpenId = JSON.toJSONString(map);
        redisTemplate.opsForValue().set("xcxLogin" + sessionKey, toOpenId, 3000, TimeUnit.MINUTES);
        return map;
    }
    @PostMapping("/authLogin")
    public R authLogin(@RequestBody Params params, String sessionKey)
    {
        if (wxConfig.getWxMaService().switchover(params.getAppId()))
        {
            throw new RuntimeException(String.format("未找到对应appid=[%s]的配置,请核实!", params.getAppId()));
        }
        // 通过 解密 加密字符串获取用户信息
        WxMaUserInfo userInfo = wxConfig.getWxMaService().getUserService()
            .getUserInfo(params.getSessionId(), params.getEncryptedData(), params.getIv());
        // 通过 解密 加密字符串获取用户手机号
        WxMaPhoneNumberInfo phoneNoInfo = wxConfig.getWxMaService().getUserService()
            .getPhoneNoInfo(params.getSessionId(), params.getEncryptedData(), params.getIv());
        String phoneNumber = phoneNoInfo.getPhoneNumber();
        return wxLoginService.authLogin(userInfo, phoneNumber, sessionKey);
    }
}