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

news/2024/5/24 12:16:10/

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直流电压的仿真系统。以下是该设计的主…

专升本-物联网

物联网&#xff08;IOT&#xff0c;Internet of things&#xff09; 体系结构&#xff1a; 感知层&#xff08;感知执行层&#xff09; 网络层 应用层 基本特征&#xff1a; 全面感知 可靠传输 智能处理 作用&#xff1a; 信息采集、转换、收集 信息传递和处理 数据…

网关冗余技术

1.第一跳冗余协议&#xff1a;FHRP HSRP、VRRP、GLBP 2.HSRP 热备份路由协议&#xff0c;思科私有协议&#xff0c;组播地址224.0.0.2&#xff0c;默认hello time3s&#xff0c;hold time 10s &#xff08;1&#xff09;原理&#xff1a; 1&#xff09;①将多台设备逻辑的…

C++中的string类模拟实现

目录 string类的模拟实现 string类的构造函数 string类拷贝构造函数 string类析构函数 string类c_str()函数 string类中的[]运算符重载函数 string类中的赋值运算符重载 string类中获取字符串有效字符个数 string类中获取字符串存储空间大小&#xff08;不包括\0&…

人工智能(pytorch)搭建模型25-基于pytorch搭建FPN特征金字塔网络的应用场景,模型结构介绍

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能(pytorch)搭建模型25-基于pytorch搭建FPN特征金字塔网络的应用场景&#xff0c;模型结构介绍。特征金字塔网络&#xff08;FPN&#xff09;是一种深度学习模型结构&#xff0c;主要应用于目标检测任务中&am…

scRNA+bulk+MR:动脉粥样硬化五个GEO数据集+GWAS,工作量十分到位

今天给大家分享一篇JCR一区&#xff0c;单细胞bulkMR的文章&#xff1a;An integrative analysis of single-cell and bulk transcriptome and bidirectional mendelian randomization analysis identified C1Q as a novel stimulated risk gene for Atherosclerosis 标题&…

Transformer的代码实现 day03(Positional Encoding)

Positional Encoding的理论部分 注意力机制是不含有位置信息&#xff0c;这也就表明&#xff1a;“我爱你”&#xff0c;“你爱我”这两者没有区别&#xff0c;而在现实世界中&#xff0c;这两者有区别。所以位置编码是在进行注意力计算之前&#xff0c;给输入加上一个位置信息…

FFMPEG对于处理rtp流出现马赛克问题处理

背景 本项目是基于FFMPEG 3.3版本进行的开发。 近期5G发展迅速&#xff0c;无线集群中的带宽不再是瓶颈&#xff0c;对于视频质量的要求也越来越高&#xff0c;现在使用720P、1080P、2K、4K进行视频通话成为了日常。 问题描述 本项目之前对于CIF和VGA格式的视频进行录…

论文笔记:基于多粒度信息融合的社交媒体多模态假新闻检测

整理了ICMR2023 Multi-modal Fake News Detection on Social Media via Multi-grained Information Fusion&#xff09;论文的阅读笔记 背景模型实验 背景 在假新闻检测领域&#xff0c;目前的方法主要集中在文本和视觉特征的集成上&#xff0c;但不能有效地利用细粒度和粗粒度…

2024年github之node排行榜top50

如果有帮助到您还请动动手帮忙点赞&#xff0c;关注&#xff0c;评论转发&#xff0c;感谢啦&#xff01;&#x1f495;&#x1f495;&#x1f495;&#x1f618;&#x1f618;&#x1f618; 本文由Butterfly一键发布工具发布 2024年github之node排行榜top50 语言star项目名称…

spring-boot集成websocket

引入Maven依赖包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>跟随spingboot版本</version> </dependency>后端代码 /*** 开启WebSocket支持*…

Gtest 和VLD一起使用报内存泄漏

这个问题已知&#xff1a; Memory Leaks on Windows using VLD Issue #2255 google/googletest GitHub 那么解决办法是什么呢&#xff1f;一个折中的办法是这样的。 TEST() {VLDMarkAllLeaksAsReported();{/// 待测代码std::string s ...;}VLDReportLeaks(); }class MyT…

一、点击视频下载(通过视频url实现);二、点击下载视频按钮,视频以压缩包形式下载(但未实现压缩视频)

一、点击视频下载&#xff08;通过视频url实现&#xff09; <div class"video-list" v-for"(item,index) in videoList" :key"index"><span class"video-title" >{{item.title}}</span><span class"video-…