java实现小程序授权登录以及获取手机号

news/2025/1/18 11:58:30/

1、引入依赖

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

2、引入封装好的工具类


import cn.binarywang.wx.miniapp.api.WxMaService;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;@Data
public class WxAppInfo {/*** 微信服务*/@JsonIgnoreprivate WxMaService wxMaService;/*** 微信App信息*/private Wxapp wxapp;
}
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import org.springframework.data.redis.core.RedisTemplate;import java.util.concurrent.TimeUnit;/*** 基于Redis的微信配置provider.*/
@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.*/@Overridepublic 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*/@Overridepublic String getAccessToken() {return redisTemplate.opsForValue().get(this.accessTokenKey);}/*** @return*/@Overridepublic boolean isAccessTokenExpired() {return redisTemplate.getExpire(accessTokenKey) < 2;}/*** @param accessToken* @param expiresInSeconds*/@Overridepublic synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {redisTemplate.opsForValue().set(this.accessTokenKey, accessToken, expiresInSeconds - 200, TimeUnit.SECONDS);}/****/@Overridepublic void expireAccessToken() {redisTemplate.expire(this.accessTokenKey, 0, TimeUnit.SECONDS);}/*** @return*/@Overridepublic String getJsapiTicket() {return redisTemplate.opsForValue().get(this.jsapiTicketKey);}/*** @return*/@Overridepublic String getCardApiTicket() {return redisTemplate.opsForValue().get(cardapiTicketKey);}
}

3、工具类

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.hutool.core.codec.Base64;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yami.shop.bean.model.Wxapp;
import com.yami.shop.service.WxAppService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Slf4j
@Configuration
public class WxMaConfiguration {private static RedisTemplate redisTemplate;private static WxAppService wxappService;private static Map<String, WxAppInfo> wxAppInfoMap = new ConcurrentHashMap<>();private static Map<String, X509Certificate> wxPlatCertMap = new ConcurrentHashMap<>();public WxMaConfiguration(RedisTemplate redisTemplate, WxAppService wxAppService) {this.redisTemplate = redisTemplate;this.wxappService = wxAppService;}/*** 获取WxMaService** @return*/public static WxAppInfo getWxAppInfo() {//替换你的获取小程序配置信息的sqlWxapp wxapp = wxappService.getOne(Wrappers.<Wxapp>lambdaQuery().orderByDesc(Wxapp::getCreateTime));WxAppInfo wxAppInfo = wxAppInfoMap.get(wxapp.getId());if (wxAppInfo != null && wxAppInfo.getWxMaService() != null) {return wxAppInfo;}WxMaInRedisConfigStorage configStorage = new WxMaInRedisConfigStorage(redisTemplate);configStorage.setAppid(wxapp.getId());configStorage.setSecret(wxapp.getSecret());WxMaService wxMaService = new WxMaServiceImpl();wxMaService.setWxMaConfig(configStorage);wxAppInfo = new WxAppInfo();wxAppInfo.setWxMaService(wxMaService);wxAppInfo.setWxapp(wxapp);wxAppInfoMap.put(wxapp.getId(), wxAppInfo);return wxAppInfo;}/*** @Description:解密手机号*/public static String decrypt(String keyStr, String ivStr, String encDataStr) {try {byte[] encData = Base64.decode(encDataStr.getBytes("GBK"));byte[] iv = Base64.decode(ivStr.getBytes("GBK"));byte[] keyByte = Base64.decode(keyStr.getBytes("GBK"));// 如果密钥不足16位,那么就补足.  这个if 中的内容很重要int base = 16;if (keyByte.length % base != 0) {int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);byte[] temp = new byte[groups * base];Arrays.fill(temp, (byte) 0);System.arraycopy(keyByte, 0, temp, 0, keyByte.length);keyByte = temp;}AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);return new String(cipher.doFinal(encData), "UTF-8");} catch (Exception e) {e.printStackTrace();}return null;}}

4、调用获取小程序openid

   /*** 小程序用户登录** @param loginDTO* @return*/@GetMapping("/login")public void login(String jsCode) {WxMaJscode2SessionResult jscode2session = null;try {jscode2session = WxMaConfiguration.getWxAppInfo().getWxMaService().jsCode2SessionInfo(jsCode);//生成accessToken方法 已经封装好直接调用即可 已做缓存处理
//            String accessToken = WxMaConfiguration.getWxAppInfo()
//                    .getWxMaService().getAccessToken();} catch (Exception e) {e.printStackTrace();}Assert.notNull(jscode2session, "用户信息获取失败,请稍后重试!");User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getOpenId, jscode2session.getOpenid()));if (null == user) {user = new User();//保存用户信息user.setOpenId(jscode2session.getOpenid());}user.setSessionKey(jscode2session.getSessionKey());userService.saveOrUpdate(user);//todo 生成toke登录信息}

5、获取手机号


import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class GetPhoneDTO {@NotBlank(message = "encryptedData is required")private String encryptedData;@NotBlank(message = "iv is required")private String iv;@NotBlank(message = "code is required")private String code;private String appId;private Long userId;}/*** 获取用户手机号** @param getPhoneDTO* @return*/
@PostMapping("/getMobile")
public void getMobile(@Valid @RequestBody GetPhoneDTO getPhoneDTO) 
{JSONObject result = JSONObject.parseObject(WxMaConfiguration.decrypt("sessionKey", getPhoneDTO.getIv(), getPhoneDTO.getEncryptedData()));String phone = result.getString("phoneNumber");
}

http://www.ppmy.cn/news/1405569.html

相关文章

28.ReentrantLock-多条件变量

synchronized中也有条件变量&#xff0c;当条件不满足时进入WaitSet等待。 ReentrantLock的条件变量比Synchronized强大之处在于它支持多个条件变量。 await和signal方法 多条件变量的使用流程 1.await需要获得锁。 2.await执行后会释放锁&#xff0c;进入ConditionObject…

Windows Edge浏览器兼容性问题诊断与修复策略详解

随着Microsoft Edge浏览器的持续迭代与更新&#xff0c;其性能与兼容性已得到了显著提升。然而&#xff0c;在面对互联网上纷繁复杂的网页内容时&#xff0c;仍有可能遇到兼容性问题。本文旨在探讨Edge浏览器在处理网页兼容性问题时的常见场景、原因分析及相应的解决方案&#…

秒验:让APP验证和登录远不只是便捷

在互联网时代&#xff0c;手机号码已成为用户在App应用中的身份标识&#xff0c;用于登录和身份核验。目前&#xff0c;大多数App应用采用短信验证码的方式进行登录&#xff0c;但这种方式存在一些缺点&#xff0c;如操作繁琐、验证码接收不及时或被截取等。随着5G时代的到来&a…

大数据设计为何要分层,行业常规设计会有几层数据

大数据设计通常采用分层结构的原因是为了提高数据管理的效率、降低系统复杂度、增强数据质量和可维护性。这种分层结构能够将数据按照不同的处理和应用需求进行分类和管理&#xff0c;从而更好地满足不同层次的数据处理和分析需求。行业常规设计中&#xff0c;数据通常按照以下…

docker导出导入镜像

docker导出镜像 查看要导出的镜像 docker images主要有两列 REPOSITORY TAG 导出命令 导出公式 docker save -o xxxx.tar REPOSITORY:TAG例子 docker save -o minio.tar minio/minio:latestminio/minio:latest可以使用image id代替&#xff0c;但是使用image id会导致导…

常州SAP实施公司有哪些值得推荐

随着信息技术的不断发展和企业管理的日益复杂&#xff0c;SAP系统在各行各业中扮演着越来越重要的角色。常州作为中国制造业的重要基地之一&#xff0c;其企业在数字化转型的道路上也越来越多地采用SAP系统&#xff0c;以提高管理效率、降低成本、优化资源配置&#xff0c;从而…

Excel中文显示问号

直接上操作步骤&#xff1a; 1&#xff09;打开Excel -> 文件 -> 选项 -> 语言 2&#xff09;Office 显示语言&#xff0c;“中文(简体)”设置为首选。 3&#xff09;Office创作语言和校对&#xff0c;“中文(简体)”设置为首选。 网上用记事本转换的方法&#xff0c;…

基于单片机20v数字电压表仿真系统设计

**单片机设计介绍&#xff0c;基于单片机20v数字电压表仿真系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机20V数字电压表仿真系统设计的主要目标是实现一个能够准确测量和显示20V直流电压的仿真系统。以下是该设计的主…