问题
I have got a Blazor WebAssembly (latest 3.2.0) app with oidc Authentication. The asp.net authentication provides a way to get the accessToken but can't see any means to access the id_token (jwt) which is required for my scenario. I can see the id_token in the local storage of the browser. What would be best way to access it?
Thanks
回答1:
You can read it from the session storage using JSInterop, it is stored at key oidc.user:{app baseUri}:{app client id} :
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
...
@code {
private async Task<string> ReadIdToken()
{
const string clientId = "your oidc client id";
var userDataKey = $"oidc.user:{NavigationManager.BaseUri}:{clientId}";
var userData = await JSRuntime.InvokeAsync<UserData>("sessionStorage.getItem", userDataKey);
return userData.id_token;
}
class UserData
{
public string id_token { get; set; }
public int expires_at { get; set; }
}
}
回答2:
Here's a working code sample that allows you to get the id_token in raw format as well as a list of claims parsed from it.
Note: You should authenticate before you can see the results...
@page "/"
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
@using System.Security.Claims
@using System.Text.Json
<p>@JwtToken</p>
@foreach (var claim in claims)
{
<p>@claim</p>
}
@code {
List<Claim> claims = new List<Claim>();
string JwtToken;
protected override async Task OnInitializedAsync()
{
await GetJwtToken();
}
private async Task GetJwtToken()
{
var baseUri = NavigationManager.BaseUri.Substring(0,
NavigationManager.BaseUri.Length - 1);
// client id example: RoleBasedApiAuthorization.Client
const string clientID = "<Place here your client id>";
var key = $"oidc.user:{baseUri}:{clientID}";
JwtToken = await JSRuntime.InvokeAsync<string>
("sessionStorage.getItem", key);
if (JwtToken != null)
{
claims = ParseClaimsFromJwt(JwtToken).ToList();
}
}
public IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
{
var payload = jwt.Split('.')[1];
var jsonBytes = ParseBase64WithoutPadding(payload);
var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes);
return keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString()));
}
private byte[] ParseBase64WithoutPadding(string base64)
{
switch (base64.Length % 4)
{
case 2: base64 += "=="; break;
case 3: base64 += "="; break;
}
return Convert.FromBase64String(base64);
}
}
回答3:
Thank you guys SO much for this - I've been banging my head against this for a week (doh - forgot to look at the browser session data in Chrome to think about using JRRuntime...).
I'm not sure if this is Cognito-specific, but the key for me is not using the NavigationManager BaseUri, but the OIDC Authority.
@page "/"
@using System.Text.Json
@inject IJSRuntime JSRuntime
<AuthorizeView>
<Authorized>
<div>
<b>CachedAuthSettings</b>
<pre>
@JsonSerializer.Serialize(authSettings, indented);
</pre>
<br/>
<b>CognitoUser</b><br/>
<pre>
@JsonSerializer.Serialize(user, indented);
</pre>
</div>
</Authorized>
<NotAuthorized>
<div class="alert alert-warning" role="alert">
Everything requires you to <a href="/authentication/login">Log In</a> first.
</div>
</NotAuthorized>
</AuthorizeView>
@code {
JsonSerializerOptions indented = new JsonSerializerOptions() { WriteIndented = true };
CachedAuthSettings authSettings;
CognitoUser user;
protected override async Task OnInitializedAsync()
{
string key = "Microsoft.AspNetCore.Components.WebAssembly.Authentication.CachedAuthSettings";
string authSettingsRAW = await JSRuntime.InvokeAsync<string>("sessionStorage.getItem", key);
authSettings = JsonSerializer.Deserialize<CachedAuthSettings>(authSettingsRAW);
string userRAW = await JSRuntime.InvokeAsync<string>("sessionStorage.getItem", authSettings?.OIDCUserKey);
user = JsonSerializer.Deserialize<CognitoUser>(userRAW);
}
public class CachedAuthSettings
{
public string authority { get; set; }
public string metadataUrl { get; set; }
public string client_id { get; set; }
public string[] defaultScopes { get; set; }
public string redirect_uri { get; set; }
public string post_logout_redirect_uri { get; set; }
public string response_type { get; set; }
public string response_mode { get; set; }
public string scope { get; set; }
public string OIDCUserKey => $"oidc.user:{authority}:{client_id}";
}
public class CognitoUser
{
public string id_token { get; set; }
public string access_token { get; set; }
public string refresh_token { get; set; }
public string token_type { get; set; }
public string scope { get; set; }
public int expires_at { get; set; }
}
}
I get serialization errors if I directly try and convert the string to classes using JSRuntme.InvokeAsync but it works fine with the JsonSerializer, that's why you see that seemingly extra step there.
来源:https://stackoverflow.com/questions/63105618/how-to-get-the-id-token-in-blazor-web-assembly