登录过程:
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;
///
/// 过期时间为7200秒
///
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;
}
///
/// 获取ticket
///
///
///
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 "";
}
}
///
/// 获取唯一的Uint32,redis不存在
///
///
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; }
}