The following code snippets provide a way to retrieve the access token issued when a user is authenticated with IdentityServer4 provider. In order to get the
access token you can use the HttpContext object, but since Blazor is SignalR-based, you'll have to do it the only time the HttpContext object is available, when the connection to your application is an HTTP connection, and not a WebSocket connection.
After retrieving the access token, you need to pass it to your Blazor app, and store it in a local storage. My code also provide a way to parse the access token, if necessary.
Add a file to the Pages folder and name it _Host.cshtml.cs
Add this code to the file:
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; }
}
Note: I've name the the PageModel class: HostAuthenticationModel
You'll need some of these:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Linq;
using System.Threading.Tasks;
- Next we have to pass the value stored in the AccessToken property to the Blazor App:
In the _Host.cshtml file add the model directive at the top portion of the file:
@model HostAuthenticationModel
Add a new attribute to the component Tag Helper like this:
param-AccessToken="Model.AccessToken"
Final result:
<app>
<component type="typeof(App)" render-mode="ServerPrerendered"
param-AccessToken="Model.AccessToken"/>
</app>
The param-AccessToken
attribute requires you to define a property named AccessToken in the App component which will get the access token from the page model.
- Next define the property which will receive the access token
And then override the OnAfterRenderAsync method from which we call a method to
store the access token in the local storage.
@code{
[Parameter]
public string AccessToken { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await tokenStorage.SetTokenAsync(AccessToken);
}
}
}
Also place the following at the top of the App component:
@inject AccessTokenStorage tokenStorage
Next you'll have to create the AccessTokenStorage service like this:
Create a class named AccessTokenStorage at the root of your app, and add the
following code:
public class AccessTokenStorage
{
private readonly 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);
}
}
}
I guess no explanation is needed here... Here's some using directives you may need
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;
Add the following to the Startup.ConfigureServices
services.AddHttpClient();
services.AddScoped<AccessTokenStorage>();
Note: the above code should be used with the code I provide in my answer here
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…