.NET微信小程序用户数据的签名验证和解密代码

微信小程序时下大热,抱着学习的心态了解了一下,目前没有搜到完整的.NET用户数据签名验证和解密代码,于是就写了一点。

简单使用方法:

1、客户端调用wx.getUserInfo方法,服务端创建WeChatLoginInfo类的实例接收客户端发来的数据;
2、服务端新建WeChatAppDecrypt类的实例,初始化此类时需传入appId与AppSecret用于验证;
3、调用WeChatAppDecrypt类中的Decrypt方法,传入步骤1中获取的WechatLoginInfo实例;
4、得到WechatUserInfo类的实例,其中就是解密好的数据。

话不多说,注释比较详尽,感兴趣的朋友可以参考。

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using System.Security.Cryptography;
using System.Text;

namespace BroadSky.WeChatAppDecrypt
{
  /// <summary>
  /// 处理微信小程序用户数据的签名验证和解密
  /// </summary>
  public class WeChatAppDecrypt
  {
    private string appId;
    private string appSecret;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="appId">应用程序的AppId</param>
    /// <param name="appSecret">应用程序的AppSecret</param>
    public WeChatAppDecrypt(string appId, string appSecret)
    {
      this.appId = appId;
      this.appSecret = appSecret;
      return;
    }

    /// <summary>
    /// 获取OpenId和SessionKey的Json数据包
    /// </summary>
    /// <param name="code">客户端发来的code</param>
    /// <returns>Json数据包</returns>
    private string GetOpenIdAndSessionKeyString(string code)
    {
      string temp = "https://api.weixin.qq.com/sns/jscode2session?" +
        "appid=" + appId
        + "&secret=" + appSecret
        + "&js_code=" + code
        + "&grant_type=authorization_code";

      return GetResponse(temp);

    }

    /// <summary>
    /// 反序列化包含OpenId和SessionKey的Json数据包
    /// </summary>
    /// <param name="code">Json数据包</param>
    /// <returns>包含OpenId和SessionKey的类</returns>
    public OpenIdAndSessionKey DecodeOpenIdAndSessionKey(WechatLoginInfo loginInfo)
    {
      OpenIdAndSessionKey oiask = JsonConvert.DeserializeObject<OpenIdAndSessionKey>(GetOpenIdAndSessionKeyString(loginInfo.code));
      if (!String.IsNullOrEmpty(oiask.errcode))
        return null;
      return oiask;
    }

    /// <summary>
    /// 根据微信小程序平台提供的签名验证算法验证用户发来的数据是否有效
    /// </summary>
    /// <param name="rawData">公开的用户资料</param>
    /// <param name="signature">公开资料携带的签名信息</param>
    /// <param name="sessionKey">从服务端获取的SessionKey</param>
    /// <returns>True:资料有效,False:资料无效</returns>
    public bool VaildateUserInfo(string rawData, string signature, string sessionKey)
    {
      //创建SHA1签名类
      SHA1 sha1 = new SHA1CryptoServiceProvider();
      //编码用于SHA1验证的源数据
      byte[] source = Encoding.UTF8.GetBytes(rawData + sessionKey);
      //生成签名
      byte[] target = sha1.ComputeHash(source);
      //转化为string类型,注意此处转化后是中间带短横杠的大写字母,需要剔除横杠转小写字母
      string result = BitConverter.ToString(target).Replace("-","").ToLower();
      //比对,输出验证结果
      return signature == result;
    }

    /// <summary>
    /// 根据微信小程序平台提供的签名验证算法验证用户发来的数据是否有效
    /// </summary>
    /// <param name="loginInfo">登陆信息</param>
    /// <param name="sessionKey">从服务端获取的SessionKey</param>
    /// <returns>True:资料有效,False:资料无效</returns>
    public bool VaildateUserInfo(WechatLoginInfo loginInfo, string sessionKey)
    {
      return VaildateUserInfo(loginInfo.rawData, loginInfo.signature, sessionKey);
    }

    /// <summary>
    /// 根据微信小程序平台提供的签名验证算法验证用户发来的数据是否有效
    /// </summary>
    /// <param name="loginInfo">登陆信息</param>
    /// <param name="idAndKey">包含OpenId和SessionKey的类</param>
    /// <returns>True:资料有效,False:资料无效</returns>
    public bool VaildateUserInfo(WechatLoginInfo loginInfo, OpenIdAndSessionKey idAndKey)
    {
      return VaildateUserInfo(loginInfo, idAndKey.session_key);
    }

    /// <summary>
    /// 根据微信小程序平台提供的解密算法解密数据
    /// </summary>
    /// <param name="encryptedData">加密数据</param>
    /// <param name="iv">初始向量</param>
    /// <param name="sessionKey">从服务端获取的SessionKey</param>
    /// <returns></returns>
    public WechatUserInfo Decrypt(string encryptedData, string iv, string sessionKey)
    {
      WechatUserInfo userInfo;
      //创建解密器生成工具实例
      AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
      //设置解密器参数
      aes.Mode = CipherMode.CBC;
      aes.BlockSize = 128;
      aes.Padding = PaddingMode.PKCS7;
      //格式化待处理字符串
      byte[] byte_encryptedData = Convert.FromBase64String(encryptedData);
      byte[] byte_iv = Convert.FromBase64String(iv);
      byte[] byte_sessionKey = Convert.FromBase64String(sessionKey);

      aes.IV = byte_iv;
      aes.Key = byte_sessionKey;
      //根据设置好的数据生成解密器实例
      ICryptoTransform transform = aes.CreateDecryptor();

      //解密
      byte [] final = transform.TransformFinalBlock(byte_encryptedData, 0, byte_encryptedData.Length);

      //生成结果
      string result = Encoding.UTF8.GetString(final);

      //反序列化结果,生成用户信息实例
      userInfo = JsonConvert.DeserializeObject<WechatUserInfo>(result);

      return userInfo;

    }

    /// <summary>
    /// 根据微信小程序平台提供的解密算法解密数据,推荐直接使用此方法
    /// </summary>
    /// <param name="loginInfo">登陆信息</param>
    /// <returns>用户信息</returns>
    public WechatUserInfo Decrypt(WechatLoginInfo loginInfo)
    {
      if (loginInfo == null)
        return null;

      if (String.IsNullOrEmpty(loginInfo.code))
        return null;

      OpenIdAndSessionKey oiask = DecodeOpenIdAndSessionKey(loginInfo);

      if (oiask == null)
        return null;

      if (!VaildateUserInfo(loginInfo, oiask))
        return null;

      WechatUserInfo userInfo = Decrypt(loginInfo.encryptedData, loginInfo.iv, oiask.session_key);

      return userInfo;
    }

    /// <summary>
    /// GET请求
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    private string GetResponse(string url)
    {
      if (url.StartsWith("https"))
        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

      HttpClient httpClient = new HttpClient();
      httpClient.DefaultRequestHeaders.Accept.Add(
      new MediaTypeWithQualityHeaderValue("application/json"));
      HttpResponseMessage response = httpClient.GetAsync(url).Result;

      if (response.IsSuccessStatusCode)
      {
        string result = response.Content.ReadAsStringAsync().Result;
        return result;
      }
      return null;
    }

  }
  /// <summary>
  /// 微信小程序登录信息结构
  /// </summary>
  public class WechatLoginInfo
  {
    public string code { get; set; }
    public string encryptedData { get; set; }
    public string iv { get; set; }
    public string rawData { get; set; }
    public string signature { get; set; }
  }
  /// <summary>
  /// 微信小程序用户信息结构
  /// </summary>
  public class WechatUserInfo
  {
    public string openId { get; set; }
    public string nickName { get; set; }
    public string gender { get; set; }
    public string city { get; set; }
    public string province { get; set; }
    public string country { get; set; }
    public string avatarUrl { get; set; }
    public string unionId { get; set; }
    public Watermark watermark { get; set; }

    public class Watermark
    {
      public string appid { get; set; }
      public string timestamp { get; set; }
    }
  }
  /// <summary>
  /// 微信小程序从服务端获取的OpenId和SessionKey信息结构
  /// </summary>
  public class OpenIdAndSessionKey
  {
    public string openid { get; set; }
    public string session_key { get; set; }
    public string errcode { get; set; }
    public string errmsg { get; set; }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解IOS微信上Vue单页面应用JSSDK签名失败解决方案

    背景 手机型号: 型号:iphone 7 / iphone xs max 版本:ios 10.3.1 / ios 12.1 微信版本:WeChat 6.7.3 问题还原: Vue应用(vue-router)上使用history模式,在某个页面内调用微信JSSDK相关API,如扫码.分享等,使用当前页面URL总会出现签名错误(invalid signature),导致API调用失败. 问题根源 Vue-Router进行路由切换的时候,总是会操作浏览器的历史记录,从而响应页面URL变化. 在JSSD

  • C# 微信支付 wx.chooseWXPay 签名错误的解决方法

    本着安全第一慎用第三方代码的原则,决定自己根据微信支付SDK写支付过程,从统一下单开始一切还算顺利,到最后JS发起支付调用时抛出"支付签名错误",下面将给出正确签名方法 这里整理出的签名函数实际是通用的,在统一下单时或支付返回验证时都可以调用 重点是非空参数才参与签名,参数名称区分大小写,排序要按照ASC顺序排列,key(密匙)永远放在最后一位 以下是原函数说明: wx.chooseWXPay({ timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用time

  • 微信开发之使用java获取签名signature

    一.前言 微信接口调用验证最终需要用到的三个参数noncestr.timestamp.signature: 接下来将会给出获取这三个参数的详细代码 本文的环境eclipse + maven 本文使用到的技术HttpClient.Json字符串转map.sha1加密 二.需要用到的jar包 maven依赖的包有: 1.HttpClient包依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <ar

  • 微信封装的调用微信签名包的类库

    废话不多说了,直接给大家贴代码了,具体代码如下所示: <?php namespace Home\Model; use Think\Model; class WechatModel extends Model { private $_token = ''; //令牌 private $appid; private $appsecret; public function __construct() { $this->appid = C('APPID');//公众号的appid $this->

  • VUE解决微信签名及SPA微信invalid signature问题(完美处理)

    前端小菜鸟,因为项目要对接微信的jssdk,对接就需要签名认证,但是无奈安卓和IOS各有各的坑,本篇文章只讨论签名,和一个分享的坑,希望大家有所收获,能够解决问题,如果解决不到,请麻烦在评论区留言,本文综合了所有的回答,才调试出来坑 需求: 使用微信的功能 原因: 1. 项目基于vue,在微信上的web应用 2. 要使用上传功能(不同系统的兼容真的很多BUG,最后只能使用微信方案),支付功能,定位.... 3. 签名一直存在bug和问题,那么后面的功能都会唤不起(偶尔也可以) 签名 1. 流程详

  • Android微信支付获取二次签名Sign的方法

    本文实例为大家分享了Android微信支付获取二次签名Sign的方法,供大家参考,具体内容如下 /** * 获取sign签名 * * @return */ private String genPayReq() { // 获取参数的值 PayReq request = new PayReq(); request.appId = ConstantsMember.APP_ID; request.partnerId = ConstantsMember.MCHID; request.prepayId =

  • 基于微信签名signature获取(实例讲解)

    微信分享的签名算法微信也写有,主要是调用接口需要使用服务器(微信官方文档是这么说的,试了下前端居然特么也可以),不过微信的access_token和jsapi_ticket是有使用次数限制的,所以还是用服务器来获取,得到以后存下来,下次使用判断超时以后再重新获取,这样就够用了,要不然就会出现接口调用次数超出限制这种尴尬的事情了. 如果需要使用自定义分享文案的时候,服务号或者订阅号一定要是已认证的(我的是个人类型的订阅号,不能认证,所以不能使用分享功能) 我这边用的是node做的后台,所以代码用的

  • 微信js sdk invalid signature签名错误问题的解决方法分析

    本文实例讲述了微信js sdk invalid signature签名错误问题的解决方法.分享给大家供大家参考,具体如下: /**最近在做微信js sdk 接口调用说明*/ ***相信很多人都遇见像我这样的问题,再加上自己只能算是半个程序员,所以苦苦摸索了好久终于搞懂了. ****下面就把自己所遇见的各种问题和大家分享一下,都是自己亲手实验过的********/ 一.问题说明 如果出现 invalid signature,首先可以确定的是你的签名算法有问题. 建议:首先查看微信官方网站给出的解决

  • 微信 jssdk 签名错误invalid signature的解决方法

    几乎每一个开发用于微信公众号页面的工程师都遇到过微信jssdk报的各种错误,通常是permission denied,类似这样: 通常他们会建议你把debug选项开开,比如这样: wechat.config({ debug: true, appId: appId, timestamp: timestamp, nonceStr: nonceStr, signature: signature, jsApiList: ['scanQRCode'], }); 结果你又遇到了invalid signatu

  • 详解Vue开发微信H5微信分享签名失败问题解决方案

    关于Vue中路由使用history模式,开发微信H5页面分享时在安卓上签名有效成功,但是在IOS设备上一直报错签名失效问题 问题描述:在Vue开发过程中,路由使用History模式下,在使用微信分享时,在微信开发者工具上一切正常.在安卓上一切正常. 但是!!!在IOS上反复报签名错误. 以下是真机测试截图,划掉黑线的是我个人IOS设备分享出来一直是服务号,接着下面分享出来自定义内容是安卓分享正常,话不多说上图!!!! 我的代码: 需求描述:需要从首页进入活动详情页,然后在详情页分享详情页面内容.

随机推荐