如何从 blazor(服务器端)网络应用程序获取访问令牌?

How do I get the access token from a blazor (server-side) web app?

实现openidconnect后,blazor将access token存放在哪里?如何取回?


https://docs.microsoft.com/en-us/aspnet/core/security/blazor/?view=aspnetcore-3.1&tabs=visual-studio#customize-unauthorized-content-with-the-router-component

以下代码片段提供了一种方法来检索用户使用 IdentityServer4 提供程序进行身份验证时颁发的访问令牌。为了得到 访问令牌,您可以使用 HttpContext 对象,但由于 Blazor 是基于 SignalR 的,因此您必须在 HttpContext 对象唯一可用时执行此操作,此时与应用程序的连接是 HTTP 连接,而不是 WebSocket 连接。

获取访问令牌后,您需要将其传递给您的 Blazor 应用,并将其存储在本地存储中。如有必要,我的代码还提供了一种解析访问令牌的方法。

  • 将文件添加到 Pages 文件夹并命名为 _Host.cshtml.cs

  • 将此代码添加到文件中:

     public class HostAuthenticationModel : PageModel
     {
         public async Task<IActionResult> OnGet()
         {
             if (User.Identity.IsAuthenticated)
             {
                var token = await HttpContext.GetTokenAsync("access_token");
                AccessToken = token;
    
             }
        return Page();
     }
    
     public string AccessToken { get; set; }
     }
    

注意:我将 PageModel 命名为 class:HostAuthenticationModel 您将需要其中一些: using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using System; using System.Linq; using System.Threading.Tasks;

  • 接下来我们必须将存储在 AccessToken 属性 中的值传递给 Blazor 应用程序:

在 _Host.cshtml 文件中,在文件的顶部添加模型指令:

@model HostAuthenticationModel

像这样向组件 Tag Helper 添加一个新属性:

param-AccessToken="Model.AccessToken"

最终结果:

 <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" 
                 param-AccessToken="Model.AccessToken"/>
 </app>

param-AccessToken 属性要求您在 App 组件 中定义一个名为 AccessToken 的 属性,它将从页面模型获取访问令牌。

  • 接下来定义将接收访问令牌的 属性
  • 然后覆盖OnAfterRenderAsync方法,我们从中调用一个方法 将访问令牌存储在本地存储中。

    @code{
       [Parameter]
       public string AccessToken { get; set; }
    
       protected override async Task OnAfterRenderAsync(bool firstRender)
       {
           if (firstRender)
            {
                await tokenStorage.SetTokenAsync(AccessToken);
            }
       }
     }
    

还将以下内容放在 App 组件的顶部:

@inject AccessTokenStorage tokenStorage
  • 接下来您必须像这样创建 AccessTokenStorage 服务:

    在您的应用程序的根目录下创建一个名为 AccessTokenStorage 的 class,并添加 以下代码:

    public class AccessTokenStorage { 私有只读 IJSRuntime _jsRuntime;

    public AccessTokenStorage(IJSRuntime jsRuntime)
    {
        _jsRuntime = jsRuntime;
    }
    
    public async Task<string> GetTokenAsync()
        => await _jsRuntime.InvokeAsync<string>("localStorage.getItem", "accessToken");
    
    public async Task SetTokenAsync(string token)
    {
        if (token == null)
        {
            await _jsRuntime.InvokeAsync<object>("localStorage.removeItem", 
                                                            "accessToken");
        }
        else
        {
            await _jsRuntime.InvokeAsync<object>("localStorage.setItem", 
                                                   "accessToken", token);
        }
    
    
     }
    }
    

我想这里不需要解释...这里有一些你可能需要的 using 指令 using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Security.Claims; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.JSInterop;

将以下内容添加到 Startup.ConfigureServices

services.AddHttpClient(); services.AddScoped<AccessTokenStorage>();

注意:以上代码要和我提供的代码一起使用

我用的是下面的方式

Startup.cs

services.AddHttpContextAccessor();

剃刀页面

@using Microsoft.AspNetCore.Http
@using Microsoft.AspNetCore.Authentication
@inject IHttpContextAccessor httpContextAccessor


@code {    
    private async Task<string> GetToken()
            => await httpContextAccessor.HttpContext.GetTokenAsync("access_token");
}

我通过添加下面 link 中列出的代码解决了这个问题。

https://docs.microsoft.com/en-us/powerapps/developer/data-platform/webapi/quick-start-blazor-server-app#prepare-the-app-to-use-azure-ad-tokens

注意:上面link中列出的步骤工作正常,但是,我做了一些对我来说更有意义的小修改。我还修改了对我来说更有意义的顺序。

步骤:

1.创建 TokenProvider class

public class TokenProvider
{
    public string AccessToken { get; set; }
}

2。使用以下内容更新 _Host.cshtml 文件:

@using Microsoft.AspNetCore.Authentication

@{
   
    var accessToken = await HttpContext.GetTokenAsync("access_token");
}

<body>
    <app>
        <component type="typeof(App)" param-AccessToken="accessToken" render-mode="ServerPrerendered" />
    </app>

3。用 DI 更新 StartUp.cs:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();

        services.AddScoped<TokenProvider>();

4.使用以下内容更新 App.razor:

@inject TokenProvider TokenProvider

@code
{
    
    [Parameter]
    public string AccessToken { get; set; }

    protected override void OnInitialized()
    {
        //Accept the parameter from _Host.cshtml and move into the Token Provider 
        TokenProvider.AccessToken = AccessToken;
        base.OnInitialized();
    }
}

5.在构造函数中创建 _tokenProvider 的实例 并用它来获取访问令牌

注意: 下面我得到的访问令牌不在 @code 块或 Blazor 页面的代码后面,但我使用的是服务 class。 (页面调用服务class)。我希望这是有道理的。同样,我建议您查看上面的 link。

    private readonly TokenProvider _tokenProvider;

    //Create tokenProvider using constructor Dependency Injection
    public HttpClientUtility(TokenProvider tokenProvider)
    {
        _tokenProvider = tokenProvider;
    }

var accessToken = _tokenProvider.AccessToken;

if (accessToken != null)
{
    _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
}

希望以上步骤对其他人有所帮助。