Blazor 服务器端,.razor 页面上的 ExternalRegister 按钮

5

是否可以将“External Registration”按钮放置在razor页面(服务器端)内?

以下代码来自ExternalRegister.cshtml,但我想将那两个注册按钮(Google、Facebook)作为Start.razor页面的一部分。这是可能的吗?

@model Aplication.Areas.Identity.Pages.Account.ExternalRegisterModel
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
    <div>
        <p>
            @foreach (var provider in Model.ExternalLogins)
            {
                <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
            }
        </p>
    </div>
</form>

我甚至尝试使用iframe,<iframe src="/ExternalRegisteration" title="ExternalRegisteration"></iframe>,但即使它正确显示,当按钮被点击时仍然无法工作。 - Krzysztof Krysztofczyk
2个回答

1

是的,在您的 Razor 页面中添加按钮是可能的。

当然,要做到这一点,您需要能够枚举可用的提供程序,这意味着您需要从 _Host.cshtml(或您托管 Blazor 应用程序的任何位置)将它们传递给您的 Blazor 应用程序。

注意:您无法传递 AuthenticationScheme 列表,因为 .NET 不会序列化它们,这就是为什么我将它们转换为 DTO ExternalProvider 的原因。

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@inject SignInManager<IdentityUser> _signInManager
@{
  var state = new InitialApplicationState
  {
      XsrfToken = Xsrf.GetAndStoreTokens(HttpContext).RequestToken,
      ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
        .ToList()
        .Select(scheme=>
           new ExternalProvider {Name=scheme.Name, DisplayName=scheme.DisplayName}
         )
  };
}
<component type="typeof(App)" param-InitialState="state" render-mode="ServerPrerendered" />

InitialApplicationStateExternalProvider是简单的数据传输对象类。

public class InitialApplicationState
{
    public string XsrfToken { get; set; }
    public IEnumerable<ExternalProvider> ExternalLogins { get; set; }
}
public class ExternalProvider
{
    public string Name { get; set; }
    public string DisplayName { get; set; }
}

现在,您需要在App.razor组件上将此数据作为Parameter接收到您的Blazor代码中

@inject InitialApplicationState InitialStateService

@code {
  [Parameter] public InitialApplicationState InitialState { get; set; } = default;

  protected override Task OnInitializedAsync()
  {
    InitialStateService.XsrfToken = InitialState.XsrfToken;
    InitialStateService.ExternalLogins = InitialState.ExternalLogins;
    return base.OnInitializedAsync();
  }
}

我们所做的只是声明一个参数InitialState,它将接收我们的InitialApplicationState - 然后我们将该状态存储在一个服务InitialStateService中,该服务在startup.cs中配置为Scoped依赖项。
builder.Services.AddScoped<InitialApplicationState>();

现在,我们在DI容器中有一个服务,用于Blazor,其中包含可用的外部身份验证提供程序列表和我们的伪造保护令牌。
我们可以在Blazor中的任何需要它的地方注入InitialApplicationState,例如Index.razor,并枚举ExternalLogins以渲染按钮。
在Blazor中,表单的声明略有不同,因为我们没有asp*指令:
@inject InitialApplicationState InitialStateService

<form id="external-account" 
      action="/Identity/Account/ExternalLogin" 
      method="post">
  <div>
    <p>
      @foreach (var provider in InitialStateService.ExternalLogins)
      {
        <button type="submit" 
                name="provider" 
                value="@provider.Name" 
                title="Log in using your @provider.DisplayName account">
          @provider.DisplayName
        </button>
      }
    </p>
  </div>
  <input name="__RequestVerificationToken" type="hidden"
        value="@InitialStateService.XsrfToken">
</form>

0

我认为最好的策略是在您的Razor PageModel(Code-Behind)中定义两个OnPost方法。例如:

    public void OnPostFaceBook(ExternalLogin provider)
{
    //your code here
}

    public void OnPostGoogle(ExternalLogin provider)
{
    //your code here
}

在您的.cshtml文件中,为每个表单分别放置两个表单,并在每个提交按钮上添加参数asp-page-handler。例如:
  <button type="submit" class="btn btn-primary" value="FaceBook" value="FaceBook" asp-page-handler="FaceBook">Log in using your FaceBook account</button>

而在其他形式中:

  <button type="submit" class="btn btn-primary" value="Google" value="Google" asp-page-handler="Google">Log in using your Google account</button>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接