Jef*_*con 6 access-token jwt openid-connect blazor blazor-webassembly
我有一个 .Net Core 3.1 WebApi 后端。
我有一个 Blazor WebAssembly 前端。
我尝试在前端(有效)登录到 AWS Cognito(设置为 OpenId 提供商),然后在每个请求上将不记名令牌 (JWT) 传递到我的后端 API,以便后端 API 可以使用以下方式访问 AWS 资源:临时凭证 (CognitoAWSCredentials)。
我能够将每个请求的承载令牌从 Blazor 前端传递到后端,但是我能找到在 Blazor 中访问的唯一令牌是访问令牌。我需要 ID 令牌才能允许后端代表我的用户生成凭据。
在我的 Blazor 代码中,我已成功注册了一个自定义 AuthorizationMessageHandler,当访问我的 API 时,它会在每个 HttpClient 的 SendAsync 上调用:
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpRequestHeaders headers = request?.Headers;
AuthenticationHeaderValue authHeader = headers?.Authorization;
if (headers is object && authHeader is null)
{
AccessTokenResult result = await TokenProvider.RequestAccessToken();
if (result.TryGetToken(out AccessToken token))
{
authHeader = new AuthenticationHeaderValue("Bearer", token.Value);
request.Headers.Authorization = authHeader;
}
logger.LogObjectDebug(request);
}
return await base.SendAsync(request, cancellationToken);
}
Run Code Online (Sandbox Code Playgroud)
这会添加访问令牌,后端会获取该令牌并对其进行验证。但是,要为 AWS 服务创建 CognitoAWSCredentials 以用于权限,我需要ID Token。
我找不到任何方法来访问 Blazor 中的 ID 令牌。
如果我直接访问后端 WebApi,它会正确地将我转发到 Cognito 进行登录,然后返回。当它出现时,HttpContext 包含“id_token”。然后可以使用它来创建我需要的 CognitoAWSCredentials。
缺少的链接是如何在 Blazor 中访问 ID 令牌,因此我可以将其作为授权 HTTP 标头的不记名令牌而不是访问令牌。
添加更多代码上下文......
string CognitoMetadataAddress = $"{settings.Cognito.Authority?.TrimEnd('/')}/.well-known/openid-configuration";
builder.Services.AddOidcAuthentication<RemoteAuthenticationState, CustomUserAccount>(options =>
{
options.ProviderOptions.Authority = settings.Cognito.Authority;
options.ProviderOptions.MetadataUrl = CognitoMetadataAddress;
options.ProviderOptions.ClientId = settings.Cognito.ClientId;
options.ProviderOptions.RedirectUri = $"{builder.HostEnvironment.BaseAddress.TrimEnd('/')}/authentication/login-callback";
options.ProviderOptions.ResponseType = OpenIdConnectResponseType.Code;
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomAccountFactory>()
;
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
string APIBaseUrl = builder.Configuration.GetSection("Deployment")["APIBaseUrl"];
builder.Services.AddSingleton<CustomAuthorizationMessageHandler>();
builder.Services.AddHttpClient(settings.HttpClientName, client =>
{
client.BaseAddress = new Uri(APIBaseUrl);
})
.AddHttpMessageHandler<CustomAuthorizationMessageHandler>()
;
Run Code Online (Sandbox Code Playgroud)
HttpRequestMessage requestMessage = new HttpRequestMessage()
{
Method = new HttpMethod(method),
RequestUri = new Uri(uri),
Content = string.IsNullOrEmpty(requestBody) ? null : new StringContent(requestBody)
};
foreach (RequestHeader header in requestHeaders)
{
// StringContent automatically adds its own Content-Type header with default value "text/plain"
// If the developer is trying to specify a content type explicitly, we need to replace the default value,
// rather than adding a second Content-Type header.
if (header.Name.Equals("Content-Type", StringComparison.OrdinalIgnoreCase) && requestMessage.Content != null)
{
requestMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(header.Value);
continue;
}
if (!requestMessage.Headers.TryAddWithoutValidation(header.Name, header.Value))
{
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Name, header.Value);
}
}
HttpClient Http = HttpClientFactory.CreateClient(Settings.HttpClientName);
HttpResponseMessage response = await Http.SendAsync(requestMessage);
Run Code Online (Sandbox Code Playgroud)
当 OpenIdConnect 中间件尝试使用 Cognito 进行授权时,它会调用:
https://<DOMAIN>/oauth2/authorize?client_id=<CLIENT-ID>&redirect_uri=https%3A%2F%2Flocalhost%3A44356%2Fauthentication%2Flogin-callback&response_type=code&scope=openid%20profile&state=<HIDDEN>&code_challenge=<HIDDEN>&code_challenge_method=S256&response_mode=query
Run Code Online (Sandbox Code Playgroud)
(隐藏:由我插入一些可能敏感的值)
仅当请求openid范围时才会返回 ID 令牌。如果请求 aws.cognito.signin.user.admin 范围,则访问令牌只能用于 Amazon Cognito 用户池。
由于我的普通用户不是管理员,因此我不请求管理范围。
因此,根据文档,Cognito 应该返回一个 ID 令牌。当我打印 Blazor 中 OIDC 中间件创建的 ClaimsPrincipal 的声明时,token_use 为id
:
{
"Type": "token_use",
"Value": "id",
"ValueType": "http://www.w3.org/2001/XMLSchema#string",
"Subject": null,
"Properties": {},
"OriginalIssuer": "LOCAL AUTHORITY",
"Issuer": "LOCAL AUTHORITY"
}
Run Code Online (Sandbox Code Playgroud)
但是,添加到 Http 请求中的 AccessToken 是 access_token。以下是token_use
添加到 HTTP 请求中的已解码 JWT 令牌的声明:
{
"Type": "token_use",
"Value": "access",
"ValueType": "http://www.w3.org/2001/XMLSchema#string",
"Subject": null,
"Properties": {},
"OriginalIssuer": "https://cognito-idp.ca-central-1.amazonaws.com/<USER-POOL-ID>",
"Issuer": "https://cognito-idp.ca-central-1.amazonaws.com/<USER-POOL-ID>"
}
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为 Blazor API ...... IAccessTokenProvider.RequestAccessToken()
似乎没有一个 API 来请求 ID 令牌。
感谢有关如何在 blazor web assembly 中获取 id_token 的答案,我能够获取 id_token。示例代码如下:
@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; }
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:但是...如果您将 id_token 与 CognitoAWSCredentials 一起使用,那么您将遇到此错误(https://github.com/aws/aws-sdk-net/pull/1603),该错误正在等待合并。如果没有它,您将无法直接在 Blazor WebAssembly 中使用 AWS 开发工具包客户端,只能将 id_token 传递到后端才能创建CognitoAWSCredentials。
归档时间: |
|
查看次数: |
3191 次 |
最近记录: |