1. 程式人生 > 其它 >在Blazor實現微信小程式掃碼登入

在Blazor實現微信小程式掃碼登入

在Blazor實現微信小程式掃碼登入

——使用極簡登入模型

最近需要開發一個Blazor Server Side頁面,需要用到登入功能,作為某微信小程式的後管。在網上搜了一遍,似乎沒有找到合適的,所以就自己造了個輪子。幾乎都是程式碼,從來不需要寫註釋的我。

  • 本文示例後端程式碼在.NET 6,下用Minimal Api實現。
  • 我是CHARSET,轉載請保留全文字。

1. Blazor前端顯示二維碼

GitHub上隨便找了個元件,名字是BlazorZXingJs。使用方法也非常簡單。將元件放入<NotAuthorized>標籤內部。

 <QRCodeWriter Text="@Code" Width="200" Heigth="200" @ref="writer" />

如果需要每隔一段時間生成,則更換Code的值即可。

2. 使用SignalR將ConnectionId從後端傳給Blazor前端

在後端SignalR.Hub接受每次連線時傳回
public override async Task OnConnectedAsync() {
  await Clients.Caller.SendAsync("ConnectionId", Context.ConnectionId);
  await base.OnConnectedAsync();
}
Blazor前端接收到ConnectionId
hubConnection.On<string>("ConnectionId", id => connectionId = id);
需要注意到的是,Blazor前端在收到此Id後才顯示二維碼
if (!string.IsNullOrEmpty(connectionId)) {
  code = Guid.NewGuid().ToString();
  Membership.RegisterScanCode(code);
  Code = $"{code}|{connectionId}";
  InvokeAsync(StateHasChanged);
}

為了簡單起見,Code使用上述邏輯生成。影象識別的結果是註冊的二維碼CodeconnectionId

3. 小程式解析快速響應碼(QRCode)

function OnQRLogin() {
  wx.scanCode({ onlyFromCamera: true, scanType: ['qrCode'],
    success: function (res) {
      const split = res.result.split('|')
      wx.request({
        url: `${host}/e/${token}/${split[0]}/${split[1]}`,
        success: function (rt) {
          if (rt.data && rt.data.success) {
            wx.showModal({ title: '成功', content: '請注意登入頁面是否成功的資訊', icon: 'success' })
          }
        }
      })
    }
  })
}

4. 後端服務根據ConnectionId將Token和二維碼Code回送給Blazor前端

application.MapGet("/e/{token}/{recog}/{cid}", async Task<SimpleResponse> 
                   (string token, string recog, string cid, [FromServices] ChatHubHelper hub) => {
  var response = new SimpleResponse();
  await hub.SendRequest(cid, new LoginRequest { ScanCode = recog, Token = token });
  response.Success = true;
  return response;
});

5. Blazor前端收到此回執後正常使用極簡模型登入

hubConnection.On<LoginRequest>("LoginRequest", async request => {
  connectionId = "已掃描,請靜待結果……";
  var response = await AuthStateProvider.Login(request);
  if (response.Success) {
    Membership.UnRegisterScanCode(code);
    await Message.Success("登入成功");
  } else {
    await Message.Warn(response.Message);
  }
  await InvokeAsync(StateHasChanged);
});

初版在2022年3月17日寫