微信小程序04: 获取openId和unionId

news2024/11/26 15:37:12

全文目录,一步到位

  • 1.前言简介
    • 1.1 专栏传送门
      • 1.1.1 上文小总结
      • 1.1.2 上文传送门
  • 2. 获取openId和unionId操作
    • 2.1 准备工作
      • 2.1.1 请先复制00篇的统一封装代码
      • 2.1.2 微信登录请求dto
    • 2.2 具体代码使用与注释如下
      • 2.2.1 业务代码
      • 2.2.2 代码解释(一)[无需复制]
      • 2.2.3 获取的map使用方式
        • unionId的解密效果图如下:
      • 2.2.4 解密功能(iv+encryptedData)
    • 2.2.5 微信接口返回值校验
      • 2.2.6 实际使用方式(一行代码)
  • 3. 文章的总结与预告
    • 3.1 本文总结
    • 3.2 下文预告


1.前言简介

1.1 专栏传送门

=> 小程序相关操作专栏 <=

1.1.1 上文小总结

上文主要是大多数微信小程序的整体封装, 代码共用, 而本篇只需要关心业务本身即可, 使用前请先复制上文的代码后使用(请看1.1.2文章传送门)

1.1.2 上文传送门

===> 微信小程序00: 公共封装配置(核心篇)

2. 获取openId和unionId操作

2.1 准备工作

2.1.1 请先复制00篇的统一封装代码

这里强调一下

请先复制核心篇: ===> 微信小程序-00 小程序统一封装类
请先阅读上一篇: ===> 微信小程序01: springboot获取accessToken方式

2.1.2 微信登录请求dto

前三个为参数 后面为业务

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import javax.validation.constraints.NotBlank;

/**
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class WxCommonReqDto {

    /**
     * 微信code
     */
    @NotBlank(message = "微信code不能为空")
    private String wxCode;

    /**
     * 微信加密数据
     */
    private String encryptedData;

    /**
     * 加密算法的初始向量
     */
    private String iv;

    /**
     * 推广标识码")
     */
    private String promotionCode;

    /**
     * 手机号
     */
    private String phone;
}

2.2 具体代码使用与注释如下

2.2.1 业务代码

流程解释:
通过wxcode获取的openid作为唯一表示 用于写登录认证逻辑
ps: 一个小程序内的openid是唯一的, 如果是多个小程序并且没有unionId, 数据库存储openid是多对一关系

public AjaxResult wxMiniLogin(WxMiniLoginReqDTO wxMiniLoginReqDTO) {

        log.info("登录参数:" + JSON.toJSONString(wxMiniLoginReqDTO));

        String phone = wxMiniLoginReqDTO.getPhone();

        /*获取微信具体信息*/
        Map<String, String> wxMiniAuthMap = wechatServiceUtils.getWxMiniAuth(wxMiniLoginReqDTO);

        //如果前端只传wxCode 没有unionId的需求 只要openId的(直接登录不需要注册)

		//TODO 业务层代码 返回登录信息token等

        log.info("===> 当前登录人token信息: {}", JSON.toJSONString(map));

        return AjaxResult.success("登录成功!", map);
    }

2.2.2 代码解释(一)[无需复制]

内置两套逻辑 openid和unionId获取信息
用type区分1是unionId 2是openId
decryptResult是字符串类型
1返回的是json字符串 2是纯字符串

public Map<String, String> getWxMiniAuth(WxCommonReqDto wxCommonReqDto) {
        String code = wxCommonReqDto.getWxCode();
        //秘钥
        String encryptedIv = wxCommonReqDto.getIv();
        //加密数据
        String encryptedData = wxCommonReqDto.getEncryptedData();

        JSONObject wxAuthResponse = null;
        String sessionKey = "";
        String openid = "";
        try {
            //1. 想微信服务器发送请求获取用户信息
            String url = wechatConfigProperties.getWxLoginUrl(code);
            log.info("===> 请求微信url是: {}", url);

            //2. 远程调用微信接口
            String res = restTemplate.getForObject(url, String.class);
            wxAuthResponse = JSONObject.parseObject(res);

            //3. 解析返回参数 报错则进行对应处理
            /*校验1: wx请求不是null*/
            if (wxAuthResponse != null) {

                /*校验2: 响应对象是否正确*/
                CheckUtils.responseCheck(wxAuthResponse);

                //3.1 获取session_key和openid
                sessionKey = wxAuthResponse.getString("session_key");
                openid = wxAuthResponse.getString("openid");
                log.info("===> openid:  {}", openid);

                /*校验3: 响应信息是否正常*/
                if (StringUtils.isBlank(sessionKey) || StringUtils.isBlank(openid)) {
                    log.error("小程序授权失败,session_key或open_id是空!");
                    throw new ServiceException("抱歉, 小程序授权失败,缺少关键返回参数!");
                }
                log.info("===> 微信回调信息: {}", wxAuthResponse);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("抱歉, 小程序授权失败!");
        }

        //4. 获取微信信息并制作token
        /*校验:(选用)如果获取union_id 需要进行解密*/
        Map<String, String> map = new HashMap<>();
        String token = "";
        if (StringUtils.isNotBlank(encryptedIv) && StringUtils.isNotBlank(encryptedData)) {
            String decryptResult = "";
            try {
                //如果没有绑定微信开放平台,解析结果是没有unionid的。
                decryptResult = AESUtils.decrypt(sessionKey, encryptedIv, encryptedData);

                if (StringUtils.hasText(decryptResult)) {
                    //如果解析成功,获取token
                    map.put("type", String.valueOf(1));
                    map.put("decryptResult", decryptResult);
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new ServiceException("微信登录失败!");
            }
        } else {
            //如果前端只传wxCode 没有unionId的需求 只要openId的
            map.put("type", String.valueOf(2));
            map.put("decryptResult", openid);
        }

        /*校验: 数据为空的情况*/
        if (StringUtils.isBlank(map.get("type")) || StringUtils.isBlank(map.get("decryptResult"))) {
            throw new ServiceException(ResponseEnum.A10007);
        }


        return map;
    }

2.2.3 获取的map使用方式

需要使用unionId的 将注释打开
获取后可以进行后续操作, 比如注册, 登录 等
wx.login()获取的code使用一次即为失效, 切记

        String openId = "";
        String nickName = "";
        String unionId = "";
        String avatarUrl = "";

        String typeStr = wxMiniAuthMap.get("type");//1 unionId 2 openId
        String decryptResult = wxMiniAuthMap.get("decryptResult");
        if (StringUtils.isBlank(typeStr) || StringUtils.isBlank(decryptResult)) {
            throw new ServiceException(ResponseEnum.A10007);
        }

        int type = Integer.parseInt(typeStr);

        /*校验: 带解密的 需要union_id的*/
        if (type == 1) {
            //字符串转json
            JSONObject jsonObject = JSONObject.parseObject(decryptResult);
            openId = jsonObject.getString("openId");//openId
            //TODO 后续支持的功能
            //      nickName = jsonObject.getString("nickName");//获取nickName
            //      unionId = jsonObject.getString("unionId");//unionId
            //      avatarUrl = jsonObject.getString("avatarUrl");//获取头像
        } else {
            openId = decryptResult;
        }
unionId的解密效果图如下:

在这里插入图片描述

2.2.4 解密功能(iv+encryptedData)

AES对称性(CBC)加密 iv偏移量
=> 传送门: AES加密简介与使用

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import javax.validation.constraints.NotNull;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;

/**
 * @author pzy
 * @description TODO
 * @version 0.1.0
 */
@Slf4j
public class AESUtils {
    // 加密模式
    private static final String ALGORITHM = "AES/CBC/PKCS7Padding";
    private static final String CHARSET_NAME = "UTF-8";
    private static final String AES_NAME = "AES";

    //解决java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CBC/PKCS7Padding
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 解密
     *
     * @param content 目标密文
     * @param key     秘钥
     * @param iv      偏移量
     * @return
     */
    public static String decrypt(@NotNull String content, @NotNull String key, @NotNull String iv) {
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            byte[] sessionKey = java.util.Base64.getDecoder().decode(key);
            SecretKeySpec keySpec = new SecretKeySpec(sessionKey, AES_NAME);
            byte[] ivByte = java.util.Base64.getDecoder().decode(iv);
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(ivByte);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
            return new String(cipher.doFinal(Base64.decodeBase64(content)), CHARSET_NAME);
        } catch (Exception e) {
            log.error("解密失败:{}", e);
            e.printStackTrace();
        }
        return StringUtils.EMPTY;
    }
    
    public static void main(String[] args) {
        //接口传入的参数
        String appid = "";
        String sessionKey = "";
        String encryptedData = "";
        String iv = "";

        String decrypt = AESUtils.decrypt(encryptedData, sessionKey, iv);
        System.out.println("解密后:" + decrypt);
    }

2.2.5 微信接口返回值校验

可以持续维护, 异常码一大堆, 这里仅有40029的响应值校验

    /**
     * 微信返回值校验
     *
     * @param wxAuthResponse
     */
    public static void responseCheck(JSONObject wxAuthResponse) {
        if (wxAuthResponse.containsKey("errcode")) {

            log.error("===> 异常回调信息: {} ", wxAuthResponse);

            /*40029 错误的wxCode*/
            if ("40029".equals(wxAuthResponse.get("errcode"))) {
                throw new ServiceException("错误的微信code!");
            }

            throw new ServiceException("抱歉, 小程序授权失败!");
        }
    }

2.2.6 实际使用方式(一行代码)

/*获取微信具体信息*/
Map<String, String> wxMiniAuthMap = wechatServiceUtils.getWxMiniAuth(wxMiniLoginReqDTO);

3. 文章的总结与预告

3.1 本文总结

  • AES加密解密
  • 微信code

3.2 下文预告

  • link码
  • 支付
  • RSA加密


@author: pingzhuyan
@description: ok
@year: 2024

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1826057.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python推导式秘籍】:一行代码的艺术,高效数据处理之道

文章目录 &#x1f68b;Python推导式&#x1f680;一、列表推导式&#x1f308;1. 了解推导式❤️2. 实践&#x1f4a5;3. 总结 &#x1f680;二、字典推导式&#x1f308;1. 了解字典推导式❤️2. 实践&#x1f4a5;3. 总结 &#x1f680;三、集合推导式&#x1f308;1. 了解集…

Qwen2的各模型性能、占用显存和推理速度比较(摘自官方文档)

Qwen2的各模型性能、占用显存和推理速度比较&#xff08;摘自官方文档&#xff09; 性能 推理速度&#xff08;从大到小&#xff09; 72B 57B-A14B 7B 1.5B 0.5B

目标检测数据集 - PCB板表面缺陷检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍&#xff1a;PCB 板表面缺陷检测数据集&#xff0c;真实采集高质量 PCB 板表面含缺陷图片数据&#xff0c;数据集含多款不同 PCB 板高清表面图片数据&#xff0c;包括俯拍正拍、旋转拍摄姿态。数据标注标签包括 missing_hole、mouse_bite、open_circuit、short、spur…

【ARM-Linux篇】阿里云人脸识别方案

一、接入阿里云 https://vision.aliyun.com/ 点击“人脸搜索1:N” 点击"立即开通"&#xff1a; 使用阿里云APP/支付宝/钉钉扫码登录&#xff1a; 购买“人脸搜索1:N”能力&#xff0c;第一次购买&#xff0c;可以有5000次的免费使用&#xff1a; 开通完后&#xff…

C++ bfS

岛屿的最大面积 . - 力扣&#xff08;LeetCode&#xff09; 1.刚开始mn又加了int 2.bfs里符合条件了&#xff0c;不push&#xff0c;&#xff0c;&#xff0c;在写什么几把 class Solution { public:int dx[4] {0, 0, 1, -1};int dy[4] {1, -1, 0, 0};bool vis[50][50];int…

学习笔记——网络管理与运维——SNMP(SNMP版本)

二、SNMP版本 1、SNMP版本 SNMP共有三个版本&#xff1a;SNMPv1、SNMPv2c和SNMPv3。 (1)SNMPv1 1990年5月&#xff0c;RFC1157定义了SNMP的第一个版本SNMPv1。RFC1157提供了一种监口控和管理计算机网络的系统方法。SNMPv1基于团体名认证&#xff0c;安全性较差&#xff0c;…

宠物健康顾问系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;顾问管理&#xff0c;用户管理&#xff0c;健康知识管理&#xff0c;管理员管理&#xff0c;论坛管理&#xff0c;公告管理 顾问账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;顾…

长亭网络通信基础

长亭笔试之前就已经学过一遍了 这算温故而知新吧 TCP/IP 首先我在这里默写一下之前的7层和4层 应用层 应 【表示层 数据格式转换 传 【会话层 …

Docker部署常见应用之SFTP服务器

文章目录 简介Dockers部署单用户多用户用户信息加密使用SSH密钥认证 参考文章 简介 atmoz/sftp 是一个基于 Docker 的 SFTP 服务镜像&#xff0c;它使用 OpenSSH 来提供 SFTP 服务。这个镜像支持创建单个或多个用户的 SFTP 访问&#xff0c;并允许用户通过 SFTP 协议安全地共享…

通信协议—Modbus

1、modbus简介 Modbus服务器&#xff1a;接收处理来自客户端的请求&#xff0c;并返回相应的响应&#xff1b; Modbus客户端&#xff1a;向Modbus服务器发送请求&#xff0c;并接收服务器返回的响应的设备或程序&#xff1b; 2、modbus poll调试工具下载 modbus poll用于测…

2024 JavaScript笔记(精简版)

系列文章目录 文章目录 系列文章目录第一章 JavaScript简介&#xff1a;1.1 特点&#xff1a;1.2 JavaScript与Java的区别1.3 JavaScript不能做什么1.4 JavaScript组成 第二章 JavaScript必备基础知识JavaScript代码调试方式 一、变量2.1.1 变量的命名规则&#xff1a;2.1.2 变…

03-appium环境配置和启动参数设置

参考文章&#xff1a;https://blog.csdn.net/lovedingd/article/details/110949993 一、appium介绍 Appium是一个开源、跨平台的自动化测试框架&#xff0c;支持Android、IOS等平台&#xff0c;同时也支持多语言&#xff0c;比如&#xff1a;Java、Python等。 Appiumu通过扩展…

【内存管理之C语言数组】

1.栈空间上的C数组 糟糕的可用性&#xff0c;但是你将在遗留代码中见到它们 相同类型的对象的内存块 大小必须是常量表达式 第一个元素索引为0 2.指针和C数组 更奇怪的是&#xff1a;数组标识符退化为指向第一个元素的指针 3.访问数组 4.堆空间上的C数组 相同类型的对象的内…

transformer模型首次体验代码

前言 首先是安装python&#xff0c;更新pip源到清华源。安装transformer pip install transformer安装jupyter lab&#xff0c;也简单一行 pip install jupyterlab现在不想用anaconda了&#xff0c;因为国内没有源了&#xff0c;国外的又慢。直接用pip吧。 然后开始体验之旅…

Go TOKEN机制与跨域处理方式

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

深入浅出 Qt 中 QListView 的设计思想,并掌握大规模、高性能列表的实现方法

在大规模列表控件的显示需求中&#xff0c;必须解决2个问题才能获得较好的性能&#xff1a; 第一就是数据存在哪里&#xff0c; 避免出现数据的副本。第二就是如何展示Item&#xff0c;如何复用或避免创建大量的Item控件。 在QListView体系里&#xff0c;QAbstractListModel解…

大数据实训项目(小麦种子)-02、实训项目整体功能介绍与演示

文章目录 前言界面及功能描述实现功能描述技术选型界面展示首页界面功能1&#xff1a;HDFS&#xff0c;选择文件上传文件详细步骤 功能2&#xff1a;MapReduce预处理数据功能3&#xff1a;Hbase存储小麦种子数据并查询前10条记录功能4&#xff1a;Hive分析原始csv文件数据并ech…

Linux C编译器从零开发二

自定义分词器 test.c #include <ctype.h> #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h>typedef enum {TK_PUNCT, // PunctuatorsTK_NUM, // Numeric literalsTK_EOF, // …

基于flask的网站如何使用https加密通信-问题记录

文章目录 项目场景&#xff1a;问题1问题描述原因分析解决步骤解决方案 问题2问题描述原因分析解决方案 参考文章 项目场景&#xff1a; 项目场景&#xff1a;基于flask的网站使用https加密通信一文中遇到的问题记录 问题1 问题描述 使用下面的命令生成自签名的SSL/TLS证书和…

BUUCTF---[MRCTF2020]你能看懂音符吗

1、下载附件&#xff0c;是一个压缩包&#xff0c;解压&#xff0c;发现解压失败 2、用winhex分析文件&#xff0c;发现文件头不对 3、将文件头改为&#xff1a;52617221&#xff0c;保存 4、解压得到word 5、在文档发现下面内容 6、根据题目的描述&#xff0c;将音乐字符解码…