<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      網站集成微信公眾號(訂閱號)登錄

      前一陣子,想著給我的站點集成一個微信登錄,因為我之前從未有過微信相關的開發,所以我自己跟著網上的資料,一步一步的慢慢的摸索,過程不免的遇到了許多坑,才把我的網站微信登錄集成完成,所以這里分享一下我的摸索的過程。因為我的是訂閱號,所以一下的內容均針對訂閱號而言的

      一、了解微信的交互流程

      這里假設我們都已經申請號了微信開發的相關信息,那么我們就要配置微信認證服務器地址(api地址),這一步是必須的,微信與我們交互都是都是通過這一個地址,開始我一直不知道,我以為自己要對每一個功能都要寫一個api,其實不需要的。我們只需要完成我們的微信認證服務器地址,然后里面處理我們相關的業務邏輯。

      sequenceDiagram 用戶->>微信: 發送消息“hello!” 微信->>我的網站: 認證服務api校驗 我的網站-)微信: 校驗成功 微信->>我的網站: 發送“hello!”到認證服務api 我的網站-)業務邏輯: 認證服務api接收“hello!”并且處理業務邏輯 我的網站-->> 用戶: 也可返回給用戶相關信息

      用我的話就是
      假設我的認證api是:/api/check
      1.用戶發送消息”你好“到微信公眾號
      2.微信公眾號發起Get請求調用 /api/check 進行認證
      3.認證成功時微信公眾號再次Post請求調用/api/check,并且攜帶”你好“信息
      4./api/check接口里面處理相關業務邏輯,或者返回特定信息給用戶

      二、集成相關sdk

      對于微信的消息處理,其實有點復雜,這里我網上搜了一下,大部分推薦的是盛派微信sdk,博客園也有相關的教程http://www.rzrgm.cn/szw/archive/2013/05/20/3089479.html,個人用起來我覺得還是可以的,可以省去我們大部分工作,專注處理業務邏輯。

      封裝CustomMessageHandler

      首先我是要對盛派微信sdk的封裝,所以我新建了一個CustomMessageHandler,然后繼承自MessageHandler,然后重新DefaultResponseMessage方法,這里比較簡單,直接

      public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage)
      {
      var responseMessage = base.CreateResponseMessage();
      return responseMessage;
      }

      處理用戶關注事件

      當微信用戶關注公眾號時我需要發送問候語給用戶,那么這里就需要重寫OnEvent_SubscribeRequestAsync
      public override Task OnEvent_SubscribeRequestAsync(RequestMessageEvent_Subscribe requestMessage)
      {
      var responseMessage = base.CreateResponseMessage();
      responseMessage.Content = “歡迎關注”;
      return Task.FromResult(responseMessage as IResponseMessageBase);
      }

      處理用戶關鍵字

      當微信用戶給公眾號發送特點消息(關鍵字)時,我需要回復用戶,那么就重寫OnTextRequestAsync
      public override Task OnTextRequestAsync(RequestMessageText requestMessage)
      {
      var responseMessage = base.CreateResponseMessage();
      return Task.FromResult(responseMessage as IResponseMessageBase);
      }

      抽離業務邏輯方法

      在開發中,我們往往希望封裝一個功能時,不需要牽扯太多業務邏輯,就例如不想在CustomMessageHandler里去寫業務邏輯,那么我這里采用的委托的形式,新建一個CustomParam,然后里面定義一個兩個委托

       public class CustomParam
          {
              /// <summary>
              /// 普通文本事件處理
              /// </summary>
              public Func<RequestMessageText, ResponseMessageText, string, ResponseMessageText> OnTextFunc;
              /// <summary>
              /// 訂閱事件處理
              /// </summary>
              public Func<string> OnSubscribeFunc;
          }
      

      然后通過CustomMessageHandler的構造函數傳入

              private CustomParam customParam;
              public CustomMessageHandler(CustomParam customParam)
              {
                  this.customParam = customParam;
              }
      

      然后在具體的處理事件里面調用這個委托

      通過接口調用微信CustomMessageHandler的方法

      我接著在建一個接口,里面包含了認證,消息處理,創建CustomMessageHandler的方法,來給業務調用

      using Core.WeXin.WxOfficial;
      using Senparc.Weixin.AspNet.MvcExtension;
      using Senparc.Weixin.MP.Entities;
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace Core.WeXin
      {
          public interface IWxCommonHandler
          {
              /// <summary>
              /// 校驗服務
              /// </summary>
              /// <returns></returns>
              bool CheckSign(string signature, string timestamp, string nonce, string echostr);
              /// <summary>
              /// 創建消息處理器
              /// </summary>
              /// <param name="inputStream"></param>
              /// <param name="messageAbsService"></param>
              void CreateMessageHandler(Stream inputStream, CustomParam param);
              /// <summary>
              /// 公眾號消息處理
              /// </summary>
              /// <param name="inputStream"></param>
              /// <returns></returns>
              Task<WeixinResult> ExecuteMessageHandler();
              /// <summary>
              /// 獲取當前opentid
              /// </summary>
              /// <returns></returns>
              string GetOpenId();
              /// <summary>
              /// 獲取微信消息
              /// </summary>
              /// <returns></returns>
              string GetMessgeText();
          }
      }
      
      
      using Core.Log;
      using Core.WeXin.WxOfficial;
      using Microsoft.Extensions.Configuration;
      using Senparc.NeuChar;
      using Senparc.NeuChar.Entities;
      using Senparc.Weixin.AspNet.MvcExtension;
      using Senparc.Weixin.MP;
      using Senparc.Weixin.MP.Entities;
      using System;
      
      namespace Core.WeXin
      {
          internal class WxCommonHandler:IWxCommonHandler
          {
              private CustomMessageHandler customMessageHandler = null;
              private IConfiguration configuration; 
              public WxCommonHandler(IConfiguration configuration)
              {
                this.configuration = configuration;
              }
              public bool CheckSign(string signature, string timestamp, string nonce, string echostr)
              {
                  string token = configuration.GetSection("SenparcWeixinSetting:Token").Value;
                  return CheckSignature.Check(signature, timestamp, nonce, token);
              }
              public void CreateMessageHandler(Stream inputStream,CustomParam customParam)
              {
                  customMessageHandler = new CustomMessageHandler(inputStream, null, customParam);
                  customMessageHandler.OmitRepeatedMessage = true;
              }
              public async Task<WeixinResult> ExecuteMessageHandler()
              {
                  await customMessageHandler.ExecuteAsync(new CancellationToken());
                  string result = "";
                  if (customMessageHandler.ResponseDocument != null)
                  {
                       result = customMessageHandler.ResponseDocument.ToString();
                  }
                  return new WeixinResult(result);
              }
      
              public string GetOpenId()
              {
                  return customMessageHandler.OpenId;
              }
              public string GetMessgeText()
              {
                  var requestMsg= customMessageHandler.RequestMessage;
                  if (requestMsg.MsgType == RequestMsgType.Text)
                  {
                      RequestMessageText requestText = requestMsg as RequestMessageText;
                      return requestText.Content;
                  }
                  return string.Empty;
              }
          }
      }
      
      

      注冊微信sdk相關內容

      using Core.Log;
      using Microsoft.AspNetCore.Builder;
      using Microsoft.Extensions.Configuration;
      using Microsoft.Extensions.DependencyInjection;
      using Newtonsoft.Json;
      using Senparc.CO2NET;
      using Senparc.CO2NET.AspNet;
      using Senparc.Weixin.AspNet;
      using Senparc.Weixin.Entities;
      using Senparc.Weixin.MP;
      using Senparc.Weixin.RegisterServices;
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace Core.WeXin
      {
          public static class ConfigureWxService
          {
              public static IServiceCollection AddWxOfficialServices(this IServiceCollection services, IConfiguration configuration)
              {
                  services.AddScoped<IWxCommonHandler, WxCommonHandler>();
                  services.AddSenparcWeixinServices(configuration);
                  return services;
              }
              public static void UseWxOfficial(this WebApplication app, ConfigurationManager configuration)
              {
                  var registerService = app.UseSenparcWeixin(app.Environment, null, null, register => { },
                      (register, weixinSetting) =>
                      {
                          register.RegisterMpAccount(weixinSetting, configuration.GetSection("WxOfficialName").Value);
                      });
              }
          }
      }
      
      

      二、新建認證api(Get請求)

      前面說到,我們和微信打交道始終是這一個微信,所以我們需要用一個api既能接收認證又能接收消息,所以我先建一個Get請求的方法

        [HttpGet("handler")]
         public ContentResult Handler()
              {
                  string signature = Request.Query["signature"];
                  string timestamp = Request.Query["timestamp"];
                  string nonce = Request.Query["nonce"];
                  string echostr = Request.Query["echostr"];
                  if (wxCommonHandler.CheckSign(signature, timestamp, nonce, echostr))
                  {
                      return new ContentResult()
                      {
                          Content = echostr
                      };
                  }
                  else
                  {
                      return new ContentResult()
                      {
                          Content = "false"
                      };
                  }
              }
      
      

      三、新建微信處理的Service

      關注事件業務

      我想在用戶關注時發送對應的問候語,則我直接新建一個方法OnSubscribeEvent

           public string OnSubscribeEvent()
              {
                  StringBuilder sb = new StringBuilder();
                  sb.Append("您好!歡迎關注【閑蛋】??\r\n");
                  sb.Append("回復[登錄]即可獲取驗證碼登錄網頁<a href=\"https://www.xiandanplay.com\">閑蛋</a>??\r\n");
                  sb.Append("更好的網站體驗請用電腦登錄????\r\n");
                  sb.Append("關于閑蛋,點這里??:<a href=\"https://mp.weixin.qq.com/s/TNBr9XiLbPJU3ZFRT3cCbg\">關于閑蛋</a>\r\n");
                  sb.Append("關于站長,點這里??:<a href=\"https://mp.weixin.qq.com/s/4KvydAbogv2KZGBfNmRveA\">關于站長</a>\r\n");
                  sb.Append("祝大家生活平平安安,不求多財但求無疾????");
                  return sb.ToString();
              }
      

      關鍵字登錄

      因為我的是訂閱號,無法獲取實現微信登錄,于是我只好通過回復關鍵字的形式,獲取登錄驗證碼,然后獲取到openid來注冊用戶,所以我的處理步驟如下:
      1.匹配到關鍵字“登錄”
      2.根據當前的當前的openid判斷redis的Set是否已有對應的驗證嗎,如果已存在直接返回“請勿重復獲取驗證碼”
      3.為了防止生成重復的有效的驗證碼,所以我新建一個Key,值為loginCode的Set類型的緩存,當生成的驗證碼可以從redis取到,則從新生成。(目前木有想到更好的辦法,請賜教...)
      4.將Set的Key、 驗證碼loginCode,放入redis,存為Set類型,過期時間為1分鐘,此處是為了步驟3的校驗
      5.再新建一個Set的Key、 openid,放入redis,過期時間為1分鐘,此處是為了步驟2的校驗,
      6.再新建一個HashSet的Key、loginCode、 openid,放入redis,過期時間為1分鐘,然后輸入驗證碼登錄的時候直接根據這個緩存來

       public ResponseMessageText OnTextEvent(RequestMessageText requestMessageText,ResponseMessageText responseMessageText,string openId)
              {
                  try
                  {
                      requestMessageText.StartHandler().Keyword("登錄", () =>
                      {
                          if (cacheClient.ExistsSet(CheckRepeatGetLoginCodeKey, openId))
                              responseMessageText.Content = $"您好:請勿重復獲取驗證碼";
                          else
                          {
                              string verCode = OnLoginVerCode(openId);
                              responseMessageText.Content = $"您好:您的網站登錄驗證碼是 {verCode} 有效期60秒";
                          }
                          return responseMessageText;
                      });
                      return responseMessageText;
                  }
                  catch (Exception ex)
                  {
                      LogUtils.LogError(ex);
                      throw;
                  }
      
              }
       private string OnLoginVerCode(string openId)
              {
                  string loginCode = StringUtil.RandomNumber(4);
                  string cacheKey = "login_wx_code";
                  bool existCode = false;
                  do
                  {
                      existCode = cacheClient.ExistsSet(cacheKey, loginCode);
                      if (!existCode)
                      {
                          TimeSpan expire = TimeSpan.FromMinutes(1);
                          cacheClient.AddSet(cacheKey, loginCode, expire);
                          cacheClient.AddSet(CheckRepeatGetLoginCodeKey, openId, expire);
                          cacheClient.AddHash(CacheKey.WxLoginCodeKey, loginCode, openId, expire);
                      }
      
                  }
                  while (existCode);
                  return loginCode;
              }
      

      四、新建認證api(Post請求)

              [HttpPost("handler")]
              public async Task<ContentResult> Handler(string signature, string timestamp, string nonce, string echostr)
              {
                  if (!wxCommonHandler.CheckSign(signature, timestamp, nonce,echostr))
                  {
                      return new ContentResult()
                      {
                          Content = "參數錯誤"
                      };
                  }
                  CustomParam customParam = new CustomParam()
                  {
                      OnSubscribeFunc = wxService.OnSubscribeEvent,
                      OnTextFunc = wxService.OnTextEvent
                  };
                  wxCommonHandler.CreateMessageHandler(Request.Body, customParam);
                  return  await wxCommonHandler.ExecuteMessageHandler();
              }
      

      wxService就是前面的封裝的方法

      五、登錄驗證

      比較簡單,就是根據驗證碼,能否從緩存取到對應的信息

                 Regex regex = new Regex(RegexPattern.IsNumberPattern);
                  if (!regex.IsMatch(code.Trim()) || code.Length != 4)
                      throw new ValidationException("code 無效");
                  CacheClient cacheClient = CacheClient.CreateClient();
                  string openId= cacheClient.GetHashValue("Wx_Login_Hash_Key", code);
                  if (string.IsNullOrEmpty(openId))
                      throw new AuthException("驗證碼無效");
                  WeXinUserInfo weXinUserInfo = new WeXinUserInfo();
                  weXinUserInfo.OpenAuthEnum = OpenAuthEnum.Wexin;
                  weXinUserInfo.Nickname = "wx_" + StringUtil.RandomNumber(10);
                  weXinUserInfo.OpenID = openId;
                  weXinUserInfo.Sex = "男";
                  cacheClient.DeleteHashField("Wx_Login_Hash_Key", code);
                  return await Task.FromResult(weXinUserInfo);
      

      六、成果展示


      目前為止,微信公眾號已經開發完成,因為我沒有過相關開發的經驗,所以如果有不合適的地方,大家可以指出來。

      同時我有個疑問請教一下大家,就是發布到服務器上后我用明文模式可以正常處理微信消息,但是安全模式卻不行了,也正確的配置了相關的EncodingAESKey

      作者:程序員奶牛

      個人開源網站:https://www.xiandanplay.com
      源碼地址:https://gitee.com/MrHanchichi/xian-dan

      posted @ 2025-02-09 17:18  灬丶  閱讀(274)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩中文字幕有码av| 亚洲情色av一区二区| 无码囯产精品一区二区免费| 欧美日韩亚洲国产| 一卡2卡三卡4卡免费网站| 精品久久精品午夜精品久久| 少妇和邻居做不戴套视频| 欧美丰满熟妇hdxx| 色综合天天综合网天天看片| 乌克兰丰满女人a级毛片右手影院| 91久久夜色精品国产网站| 亚洲AV高清一区二区三区尤物| 亚洲高清av一区二区| 久久婷婷综合色一区二区| 中文字幕在线精品国产| 免费播放一区二区三区| 无码国模国产在线观看免费| 久久精品无码精品免费专区| 自拍视频亚洲精品在线| 动漫AV纯肉无码AV电影网| 成年女人永久免费观看视频 | 香港三级韩国三级日本三级| 国精品午夜福利不卡视频| 国产一区二区三区黄色片| 丰满人妻被黑人猛烈进入| 国产精品熟妇视频国产偷人| 亚洲综合激情五月色一区| 国产精品户外野外| 五月婷婷久久中文字幕| 日本韩国日韩少妇熟女少妇| 人人妻人人狠人人爽| 无码人妻久久一区二区三区app| 日本五十路熟女一区二区| 伊人久久大香线蕉AV网| 中文字幕va一区二区三区| 欧洲中文字幕一区二区| 国产在线观看91精品亚瑟| 一区一区三区产品乱码| 亚洲av无码精品蜜桃| 欧美黑人又粗又大又爽免费| 国内精品无码一区二区三区|