[英]"Authorization failed. AuthenticationScheme: AzureADJwtBearer was challenged" in ASP.NET Core 3.1 Web API - 401 Unauthorized
[英]Asp .net Core 3.1 transforming ClaimsIdentity with multiple AuthenticationScheme
在 ASP.Net Core 應用程序中實現幾個授權方案時,我遇到了一個問題。 可以說它們在 Startup.cs 中是這樣聲明的
public void ConfigureServices(IServiceCollection services)
{
AuthenticationBuilder builder = services
.AddAuthentication()
.AddBasicAuthentication(o => { o.Realm = "MyRealm"; })
.AddApiKeyAuthentication()
.AddBearerToken(opt => { });
}
這些方案中的每一個都提供了自己的AuthenticationHandler實現,如果成功則返回ClaimsIdentity 。 但在每種情況下,聲明的結構都是不一致的,即 ApiKeyAuthentication 可能會返回ClaimsIdentity以及存儲在聲明“api_service”中的業務敏感數據,而 BearerTokenScheme 會將其存儲在聲明“sub”中,而我無法控制這一點。 因此,如果我想在 controller 中使用此信息來將某些進程與調用了我的 api 方法的服務相關聯,我必須實現一些復雜的邏輯來分析當前的ClaimsIdentity 、其身份驗證方案和聲明集。 相反,我想實現某種將 ClaimsIdentity 轉換為MyServiceClaimsIdentity的方式,這將以方便的方式公開聲明,以便我可以在控制器代碼中輕松使用它們:
public class MyServiceClaimsIdentity: IIdentity
{
private readonly ClaimsIdentity innerIdentity;
public Guid? UserId {get; }
public string UserName {get; }
public string ServiceName {get; }
public MyServiceClaimsIdentity(ClaimsIdentity identity)
{
this.innerIdentity = identity;
TransformClaimsIntoProperties();
}
private void TransformClaimsIntoProperties()
{
......
}
}
我試圖實現某種“變革性” AuthenticationHandler ,它會在所有其他處理程序產生它們的 ClaimsIdentity 之后產生MyServiceClaimsIdentity 。
public class FinalAuthenticationHandler : AuthenticationHandler<FinalAuthenticationOptions>
{
public FinalAuthenticationHandler(
IOptionsMonitor<FinalAuthenticationOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!this.Context.User.Identity.IsAuthenticated)
{
return null;
}
var identity = new MyServiceClaimsIdentity(this.Context.User.Identity);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, this.Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
在這一點上太糟糕了this.Context.User.Identity沒有用戶的任何信息,所以我很困惑將這個轉換邏輯放在哪里,或者我將如何在我的 FinalAuthenticationHandler 中獲得其他 Handler 提供的當前ClaimsIdentity 。 任何幫助,將不勝感激。
實施 IClaimsTransformation 並將其注冊為 Singleton 做得很好
internal sealed class ClaimsTransformation : IClaimsTransformation
{
private readonly IDictionary<string, IClaimsHandler> handlersMap;
public ClaimsTransformation(IEnumerable<IClaimsHandler> handlers)
{
if (handlers == null)
{
throw new ArgumentNullException(nameof(handlers));
}
this.handlersMap = handlers.ToDictionary(t => t.SchemeName);
}
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
if (!(principal.Identity is ClaimsIdentity claimsIdentity))
{
throw new InvalidOperationException($"Principal.Identity is of type {principal.Identity.GetType()}, expected ClaimsIdentity");
}
if (!this.handlersMap.TryGetValue(principal.Identity.AuthenticationType, out var handler))
{
throw new AuthenticationException($"Scheme of type {principal.Identity.AuthenticationType} is not supported");
}
var result = new ClaimsPrincipal(handler.Handle(claimsIdentity));
return Task.FromResult(result);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.