文章目录
-
- [一. 微信小程序授权登录](#一. 微信小程序授权登录)
-
- 引入依赖
- 修改配置文件
- 配置类Properties
- 配置类Config
- Controller控制器代码
- Service接口层代码
- ServiceImpl实现层代码
- [统一响应类 R](#统一响应类 R)
- 具体授权登录代码
一. 微信小程序授权登录
引入依赖
java
<!--微信小程序-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
<version>4.3.0</version>
</dependency>
修改配置文件
yaml
wx:
# 微信小程序appid
app-id: wxcbxxxxxxxxxxxxxxx
# 小程序密钥
app-secret: 8ccxxxxxxxxxxxxxxxx
msgDataFormat: JSON
配置类Properties
java
import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author:Ccoo
* @Date:2024/3/21 20:40
*/
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "wx")
public class WxProperties {
/**
* 设置微信小程序的appid
*/
private String appId;
/**
* 设置微信小程序的Secret
*/
private String appSecret;
/**
* 消息格式,XML或者JSON
*/
private String msgDataFormat;
}
配置类Config
java
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.api.impl.WxMaUserServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxRuntimeException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Objects;
@Slf4j
@Configuration
public class WxMaConfiguration {
@Resource
private WxProperties wxProperties;
@Bean
public WxMaService wxMaService() {
if (Objects.isNull(wxProperties)) {
throw new WxRuntimeException("请添加下相关配置, 注意别配错了!");
}
WxMaService maService = new WxMaServiceImpl();
try {
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid(wxProperties.getAppId());
config.setSecret(wxProperties.getAppSecret());
config.setMsgDataFormat(wxProperties.getMsgDataFormat());
HashMap configMap = new HashMap<>();
configMap.put(config.getAppid(), config);
maService.setMultiConfigs(configMap);
} catch (Exception e) {
throw new WxRuntimeException("微信小程序相关配置配置失败!");
}
return maService;
}
}
Controller控制器代码
java
import com.itheima.mp.domain.R;
import com.itheima.mp.service.WeChatService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author Ccoo
* @since 2023-10-01
*/
@RestController
@RequestMapping("/wechat")
public class WeChatController {
@Autowired
private WeChatService wechatService;
@ApiOperation(value = "微信小程序授权登录", notes = "微信小程序授权登录")
@PostMapping("/wxLogin")
public R<?> wxLogin(@ApiParam("loginCode") @RequestParam String code) {
return wechatService.wxLogin(code);
}
}
Service接口层代码
java
import com.itheima.mp.domain.R;
/**
* @author Ccoo
* 2024/8/23
*/
public interface WeChatService {
/**
* 微信授权登录
* @param code 授权码
* @return 结果
*/
R<?> wxLogin(String code);
}
ServiceImpl实现层代码
java
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.stereotype.Service;
/**
* @author Ccoo
* 2024/8/23
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class WeChatServiceImpl implements WeChatService {
private final WxMaService wxMaService;
/**
* 微信授权登录
*
* @param code 授权码
* @return 结果
*/
@Override
public R<?> wxLogin(String code) {
try {
WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
String info = JSONUtil.toJsonStr(sessionInfo);
log.info("微信授权登录成功:{}", info);
return R.ok(info);
} catch (WxErrorException e) {
log.error("微信授权登录失败:{}", e.getError().getErrorMsg());
return R.fail(e.getError().getErrorCode(), e.getError().getErrorMsg());
}
}
}
统一响应类 R
java
import java.io.Serializable;
/**
* 响应信息主体
*
* @author Ccoo
*/
public class R<T> implements Serializable
{
private static final long serialVersionUID = 1L;
/** 成功 */
public static final int SUCCESS = 200;
/** 失败 */
public static final int FAIL = 500;
private int code;
private String msg;
private T data;
public static <T> R<T> ok()
{
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> ok(String msg)
{
return restResult(null, SUCCESS, msg);
}
public static <T> R<T> ok(T data)
{
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data, String msg)
{
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail()
{
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg)
{
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data)
{
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> fail(T data, String msg)
{
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg)
{
return restResult(null, code, msg);
}
private static <T> R<T> restResult(T data, int code, String msg)
{
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode()
{
return code;
}
public void setCode(int code)
{
this.code = code;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
}
具体授权登录代码
微信小程序授权登录思路 :
- 先判断Redis中缓存是否命中, 如果命中则直接返回缓存信息
- 如果未命中缓存, 则使用临时校验码code去微信换取openid
- 查询数据库该openid对应用户信息是否存在, 存在则直接返回, 不存在则注册用户信息
- 最后将用户信息存入redis, 并返回相应的token供下次授权登录前判断是否缓存信息
具体实现代码如下
java
@ApiOperation("微信授权登录")
@PostMapping("/customer_login")
public R<SysWxUser> customerLogin(@RequestBody WXAuth wxAuth) {
return weixinService.customerLogin(wxAuth);
}
java
R<SysWxUser> customerLogin(WXAuth wxAuth);
java
/**
* 授权登录
*
* @param wxAuth 授权信息
* @return 结果
*/
@Override
public R<SysWxUser> customerLogin(WXAuth wxAuth) {
String code = wxAuth.getCode();
String iv = wxAuth.getIv();
String token = wxAuth.getToken();
String encryptedData = wxAuth.getEncryptedData();
if(StrUtil.isBlank(code) && StrUtil.isBlank(token)){
return R.fail(MessageConstants.PARAMS_ERROR);
}
// 判断登录态是否在有效期
if(StrUtil.isNotBlank(token)){
// token不为空 判断token是否过期
String content = redisTemplate.opsForValue().get(RedisKey.WX_SESSION_KEY + token);
if(content == null){
return R.fail(MessageConstants.TOKEN_NOT_EXIST);
}
// 查询token对应用户信息
SysWxUser info = JSONUtil.toBean(content, SysWxUser.class);
// 刷新token有效时间
redisTemplate.opsForValue().set(RedisKey.WX_SESSION_KEY + token, content, 3600, TimeUnit.SECONDS);
return R.ok(info);
}
SysWxUser wxUser = null;
WxMaJscode2SessionResult sessionInfo = null;
try {
sessionInfo = wxMaService.getUserService().getSessionInfo(code);
WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionInfo.getSessionKey(), encryptedData, iv);
String openid = sessionInfo.getOpenid();
// 使用微信openId查询是否有此用户(WxUser)
wxUser = lambdaQuery().eq(SysWxUser::getOpenid, openid).one();
// 不存在 构建用户信息进行注册
if(wxUser == null) {
wxUser = new SysWxUser();
wxUser.setOpenid(openid);
wxUser.setWxName(Constants.WX_PREFIX + RandomUtil.randomString(6));
wxUser.setAvatarUrl(userInfo.getAvatarUrl());
int insert = wxUserMapper.insert(wxUser);
if (insert == 0) {
return R.fail(MessageConstants.USER_BIND_ERROR);
}
}
} catch (Exception e) {
e.printStackTrace();
log.error(MessageConstants.SYSTEM_ERROR);
}
String sessionKey = sessionInfo.getSessionKey();
String cacheKey = RedisKey.WX_SESSION_KEY + sessionKey;
// 将 openid / sessionKey 存入redis
redisTemplate.opsForValue().set(cacheKey, JSONUtil.toJsonStr(wxUser), 3600, TimeUnit.SECONDS);
return R.ok(wxUser,Constants.TOKEN_PRE + sessionKey);
}