如何从 blazor(服务器端)Web 应用程序获取访问令牌?
Posted
技术标签:
【中文标题】如何从 blazor(服务器端)Web 应用程序获取访问令牌?【英文标题】:How do I get the access token from a blazor (server-side) web app? 【发布时间】:2020-05-10 11:31:43 【问题描述】:实现 openidconnect 后,blazor 将访问令牌存储在哪里?如何找回?
How to add OpenIdConnect via IdentityServer4 to ASP.NET Core ServerSide Blazor web app?
https://docs.microsoft.com/en-us/aspnet/core/security/blazor/?view=aspnetcore-3.1&tabs=visual-studio#customize-unauthorized-content-with-the-router-component
【问题讨论】:
我仍在尝试为“您将如何处理访问令牌到期?”的解决方案。这非常困难...我会尽快回答您当前的问题...顺便说一句,您想要访问令牌做什么? 我想将 id 令牌交换为(客户端凭据)访问令牌(如果我无法弄清楚,我将不得不换一种方式) 我仍然可以推荐这个博客:mcguirev10.com/2019/12/15/…. 我通过添加此链接中的代码解决了这个问题:docs.microsoft.com/en-us/powerapps/developer/… 【参考方案1】:以下代码 sn-ps 提供了一种方法来检索用户通过 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 类命名为:HostAuthenticationModel
您将需要其中一些:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Linq;
using System.Threading.Tasks;
在 _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 的类,并添加 以下代码:
公共类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>();
注意:以上代码需配合我提供的代码in my answer here使用
【讨论】:
我仍在研究“您将如何处理访问令牌到期?”的解决方案。 .请在几天后发布一个问题。 哇,干得好!顺便说一句,您这样做是为了回答这个问题,还是您还需要为自己的应用检索访问令牌? 很高兴能提供帮助!...我正在做这件事作为我学习 Blazor 的一部分。就个人而言,我不需要它,但我通过在这里解决大量问题来增加我的知识。如果它解决了您的问题,您是否介意将其标记为答案,以便其他人知道它很有用。 测试过,可以!但是你在哪里使用这个? services.AddHttpClient(); 对不起...是的,这里不需要httpclient。然而,在我的应用程序中,我使用它来测试对 Web api 的 http 调用。把它删掉吧……【参考方案2】:我通过添加下面链接中列出的代码解决了这个问题。
https://docs.microsoft.com/en-us/powerapps/developer/data-platform/webapi/quick-start-blazor-server-app#prepare-the-app-to-use-azure-ad-tokens
注意:上面链接中列出的步骤工作正常,但是,我做了一些对我更有意义的小修改。我还修改了对我更有意义的顺序。
步骤:
1.创建 TokenProvider 类
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 页面后面的代码中,但我使用的是 Service 类。 (页面调用服务类)。我希望这是有道理的。同样,我建议您查看上面的链接。
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);
希望以上步骤对其他人有所帮助。
【讨论】:
提供的链接是官方的方式,它相当简单,应该是公认的答案;) @Richard 我已按照您的步骤进行操作.. 我在第 5 步中感到震惊,您在构造函数 DI 中提到了_tokenProvider
。你能详细说明一下吗?
@Richard ***.com/q/66325590/4337436 我在这里提出了我的问题。如果可以,请帮助我。
@BalagurunathanMarimuthu 抱歉,我直到最近才知道。回顾你上面的帖子,看起来你已经通过了。
@Richard 我在访问TokenProvider
时总是收到null
值。请为此提供帮助。【参考方案3】:
我用了以下方式
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");
【讨论】:
为什么是-1?缺乏解释?不工作?不好的做法? -1 有两个原因。 1. 这对我不起作用。我的 OnPrem 解决方案具有上述代码并且可以正常工作。但是,当我部署到 Azure 时,此解决方案不起作用。以上是我如何让它在 Azure 中工作的详细帖子。 2. 我读过很多帖子说从 HttpContextAccessor / HttpContext 获取访问令牌不是一个好习惯。以上是关于如何从 blazor(服务器端)Web 应用程序获取访问令牌?的主要内容,如果未能解决你的问题,请参考以下文章
如何从服务器端 Blazor 应用程序中的 Blazor 组件调用 razor 页面而不导致页面刷新
如何通过 IdentityServer4 将 OpenId Connect 添加到 ASP.NET Core 服务器端 Blazor Web 应用程序?