c# - .Net Core 自定义身份验证使用 Identity Server 4 的 API key

标签 c# asp.net-core jwt asp.net-identity identityserver4

我有一个使用 JWT token 进行身份验证的 .NET Core 2.2 Web API。 token 由 Identity Server 4 在单独的 API 上生成。

所有身份验证和授权都按预期使用 JWT token 进行。但我需要扩展它以允许使用 API key 。如果提供了 API key ,我想加载该特定用户的声明,将其添加到请求中并让 Authorize 属性处理设置的策略。

这是我到目前为止根据 here 的建议所做的工作.我的错误与链接的帖子完全相同,它也适用于我使用具有一组角色的 GenericPrincipal 但我使用的是 AuthorisationPolicies 并且我当前的实现总是出现 401 错误,给我的错误类似于上面的链接。

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvcCore(options =>
        {
            options.Filters.Add(new RequireHttpsAttribute());
            options.Filters.Add(new AuthorizeFilter());
            options.Filters.Add(typeof(ValidateModelStateAttribute));
            options.AllowEmptyInputInBodyModelBinding = true;
        })
        .AddAuthorization(options =>
        {
            options.AddPolicies();
        })
        .AddJsonFormatters();

        services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = Configuration["Authentication:Authority"];
                options.RequireHttpsMetadata = true;
                options.ApiName = Configuration["Authentication:ApiName"];
            });
        services.AddCors();
    }

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseCors(policy =>
        {
            policy.AllowAnyHeader();
            policy.AllowAnyMethod();
            policy.AllowAnyOrigin();
        });

        app.UseHttpsRedirection();
        app.UseMiddleware<ApiKeyMiddleware>();
        app.UseAuthentication();
        app.UseMvc();
    }

AuthorizationPolicies.cs

public static class AuthorizationPolicies
{
    public const string ReadUsersPolicy = "ReadUsers";
    public const string EditUsersPolicy = "EditUsers";

    public static void AddPolicies(this AuthorizationOptions options)
    {
        options.AddPolicy(ReadUsersPolicy, policy => policy.RequireClaim(Foo.Permission, Foo.CanReadUsers));
        options.AddPolicy(EditUsersPolicy, policy => policy.RequireClaim(Foo.Permission, Foo.CanEditUsers));
    }
}

ApiKey中间件

public class ApiKeyMiddleware
{
    public ApiKeyMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    private readonly RequestDelegate _next;

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Path.StartsWithSegments(new PathString("/api")))
        {
            if (context.Request.Headers.Keys.Contains("ApiKey", StringComparer.InvariantCultureIgnoreCase))
            {
                var headerKey = context.Request.Headers["ApiKey"].FirstOrDefault();
                await ValidateApiKey(context, _next, headerKey);
            }
            else
            {
                await _next.Invoke(context);
            }
        }
        else
        {
            await _next.Invoke(context);
        }
    }

    private async Task ValidateApiKey(HttpContext context, RequestDelegate next, string key)
    {
        var userClaimsService = context.RequestServices.GetService<IUserClaimsService>();
        List<string> permissions = (await userClaimsService.GetAllPermissionsForApiKey(key))?.ToList();
        if (permissions == null)
        {
            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            await context.Response.WriteAsync("Invalid Api Key");
            return;
        }

        ICollection<Claim> claims = permissions.Select(x => new Claim(FooClaimTypes.Permission, x)).ToList();
        var identity = new ClaimsIdentity(claims);
        var principal = new ClaimsPrincipal(identity);
        context.User = principal;
        await next.Invoke(context);
    }
}

UsersController.cs

[Authorize(AuthorizationPolicies.EditUsersPolicy)]
    public async Task<IActionResult> Put([FromBody] UserUpdateDto userUpdateDto)
    {
        ...
    }

最佳答案

显然,我必须在 ClaimsIdentity 上将 AuthenticationType 设置为 Custom,如 here 所述.

var identity = new ClaimsIdentity(claims, "Custom");

关于c# - .Net Core 自定义身份验证使用 Identity Server 4 的 API key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55151764/

相关文章:

c# - 使用C#进行颜色检测

c# - objConnect.Sql = Properties.Settings.Default.SQL 中的错误;

c# - ASP .NET Core - 以其他用户身份登录/模拟用户并返回

ruby-on-rails - 在 Rails 5.2 应用程序和 Golang 之间共享网络 session

c# - IDictionary`2 不能从 IDictionary 分配?

c# - ASP.Net 错误响应为空

c# - .NET Core 应用程序,在 Kestrel 上自托管 Razor Web 应用程序,能否在完整的 .NET 和引用 system.web 上运行?

asp.net-core - 如何使用 Entity Framework 添加具有 REST 操作的 API Controller ?

Symfony JWT - 使用 symfony lexik JWT 身份验证包更改登录方式

python - WebSocket JWT Token 连接授权