C#怎么开发一个微信公众号扫码登录的功能

在这里插入图片描述

登录过程:

1.通过调用WxLogin接口获得生成二维码图片的地址和用户登录生成的token,获取一次生成的二维码有效期是60s,过期则二维码不可使用,需要设计为用户重新手动刷新获取。这样减少频繁请求接口

2.生成二维码一但被用户用微信扫描,则需要关注公众号,如果已经关注则直接提示扫码成功。这时候后台用户登录信息会被更新,前端需要间隔1~2s时间去请求Scan接口,获取用户登录信息
获取成功,会返回所有该用户的登录信息

后端开发:
封装了一个去获取token的方法

using Common;
using Newtonsoft.Json;
using System.Web;
using System.Xml.Linq;

namespace AIServer.Common
{
    public class AccessTokenHelper
    {
        private static DateTime CreateAccessTokenTime;
        /// <summary>
        /// 过期时间为7200秒
        /// </summary>
        private static int Expires_Period = 7200;

        private static string Access_Token = "";

        public static async void SetAccessToken()
        {
            Access_Token = await GetAccess_token();
        }

        public static async Task<string> GetAccessToken()
        {
            ///空的时候直接获取
            if (string.IsNullOrEmpty(Access_Token))
            {
                Access_Token = await GetAccess_token();
                CreateAccessTokenTime = DateTime.Now;
            }
            else
            {
                //1小时59分钟更新一次
                if (CreateAccessTokenTime.AddHours(2).AddSeconds(-60) <= DateTime.Now)
                {
                    Access_Token = await GetAccess_token();
                    CreateAccessTokenTime = DateTime.Now;
                }

            }
            return Access_Token;
        }


        private static async Task<string> GetAccess_token()
        {
            var clientId = "wxxxxxxxxxxxxx";
            var clientSecret = "fa8288888888888888";

            var tokenEndpoint = "https://api.weixin.qq.com/cgi-bin/token";

            var requestParams = new Dictionary<string, string>
            {
                { "grant_type", "client_credential" },
                { "appid", clientId },
                { "secret", clientSecret }
            };

            HttpClient httpClient = new HttpClient();
            var response = await httpClient.PostAsync(tokenEndpoint, new FormUrlEncodedContent(requestParams));

            if (response.IsSuccessStatusCode)
            {
                var responseString = await response.Content.ReadAsStringAsync();
                NLogHelper.Info("responseString+" + responseString);
                var responseObject = JsonConvert.DeserializeObject<dynamic>(responseString);
                var accessToken = responseObject?.access_token ?? "";
                return accessToken;
            }

            return "";
        }

    }
}

接口编写:

using AIServer.Common;
using AIServer.Models;
using Common;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using NLog.Fluent;
using OpenAI.GPT3.Managers;
using System.Net.Sockets;

namespace AIServer.Controllers
{
    [ApiController]
    [EnableCors("any")]
    [Route("[controller]")]
    public class WxLoginController : Controller
    {
        private readonly ILogger<WxLoginController> _logger;
        string Wx_Url = "";

        public WxLoginController(ILogger<WxLoginController> logger)
        {
            _logger = logger;
            string accessToken = AccessTokenHelper.GetAccessToken().Result;
            Wx_Url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;
        }

        [HttpPost(Name = "WxLogin")]
        public MessageModel<WXToClientModel> WxLogin(int LoginSysId)
        {
            var uintToken = GetGuidUINT32();
            string token = uintToken.ToString();
         
            string ticket = GetTicket(uintToken);
            WXToClientModel wXToClientModel = new WXToClientModel();
            string url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
            wXToClientModel.url = url;
            wXToClientModel.loginToken = token;
            string json = JsonConvert.SerializeObject(wXToClientModel);
            NLogHelper.Info(json);

            //用户信息存储到redis,60s过期
            UserModel user = new UserModel();
            user.ScanTime = DateTime.Now;
            user.UserToken = token;
            user.UserTicketUrl = url;
            user.UserType = LoginSysId;
            string userJson = JsonConvert.SerializeObject(user);
            KeyWordListHelper.redisDataHelper?.SetValue(token, userJson, 60);

            MessageModel<WXToClientModel> returnModel = new MessageModel<WXToClientModel>();
            returnModel.Code = "0";
            returnModel.Message = "Success";
            returnModel.Content = wXToClientModel;

            return returnModel;
        }

        /// <summary>
        /// 获取ticket
        /// </summary>
        /// <param name="scene"></param>
        /// <returns></returns>
        private string GetTicket(uint scene)
        {
            try
            {
                WXLoginModel login = new WXLoginModel();
                login.expire_seconds = 60;
                login.action_name = "QR_SCENE";
                login.action_info = new WXLoginInfoModel();
                login.action_info.scene = new WXLoginSceneModel();
                login.action_info.scene.scene_str = "";
                login.action_info.scene.scene_id = scene;
                string json = JsonConvert.SerializeObject(login);
                var data = ApiHelper.Post(Wx_Url, json);
                WXLoginTicketModel? ticket = JsonConvert.DeserializeObject<WXLoginTicketModel>(data);
                if (ticket == null)
                    return "";
                else
                    return ticket.ticket;
            }
            catch (Exception ex)
            {
                NLogHelper.Info("GetTicket" + ex.Message);
                return "";
            }

        }


        /// <summary>
        /// 获取唯一的Uint32,redis不存在
        /// </summary>
        /// <returns></returns>
        private static uint GetGuidUINT32()
        {
            var uintToken = UINTCreate.Create();
            string token = uintToken.ToString();
            //判断是否唯一
            bool isExist = true;
            while (isExist)
            {
                var isHasKey = KeyWordListHelper.redisDataHelper?.KeyExists(token);
                if (isHasKey == null)
                    isExist = false;
                else
                {
                    if (isHasKey.Value)
                    {
                        uintToken = UINTCreate.Create();
                        token = uintToken.ToString();
                    }
                    isExist = isHasKey.Value;
                }
            }
            return uintToken;
        }

    }
}

前端调用示例

前端需要做2件事情,第一获得后台推送生成的图片二维码,第二定时刷新后端的状态接口,得知是否有没有扫码成功

这边会用C#的客户端写一个demo,实际项目里,无论子啊web还是其他任何端,都是一样的原理

      public WXToClientModel? GetUrl()
      {
          string url = "http://ai.xxx.com/WxLogin?LoginSysId=" + SYSId;
          var data = APIHelper.Post(url, "");
          MessageModel<WXToClientModel>? dataJson = JsonConvert.DeserializeObject<MessageModel<WXToClientModel>>(data);
          if (dataJson != null)
          {
              if (dataJson.Code == "0")
              {
                  if (dataJson.Content != null)
                  {
                      Token = dataJson.Content.loginToken;
                      return dataJson.Content;
                  }
              }
          }
          return null;

      }
      private void timer2_Tick(object sender, EventArgs e)
      {
          string url = "http://ai.xxx.com/Scan?token=" + Token;
          var data = APIHelper.Get(url);

          MessageModel<UserModel>? user = JsonConvert.DeserializeObject<MessageModel<UserModel>>(data);
          if (user != null)
          {
              if (user.Code == "0")
              {
                  if (user.Content != null)
                  {
                      if (user.Content.IsLogin)
                      {
                          timer1.Stop();
                          timer2.Stop();
                          MessageBox.Show("登录成功");
                      }
                  }
              }
          }
      }
  public class WXToClientModel
  {
      public string loginToken { get; set; } = string.Empty;
      public string url { get; set; } = string.Empty;
  }

  public class MessageModel<T>
  {
      public string? Code { get; set; }

      public string? Message { get; set; }

      public T? Content { get; set; }
  }
  • 40
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搬砖的诗人Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值