ASP.NET Core 5.0 WebAPI 中的多种身份验证方案

     2023-03-27     245

关键词:

【中文标题】ASP.NET Core 5.0 WebAPI 中的多种身份验证方案【英文标题】:Multiple authentication schemes in ASP.NET Core 5.0 WebAPI 【发布时间】:2022-01-04 08:19:03 【问题描述】:

我有一整套在 .NET 5.0 中开发的 (ASP.NET Core) Web API,并实现了 Cookie 和 OpenIdConnect 身份验证方案。 使用 Azure AD 成功验证(用户 ID 和密码)后,会生成 cookie 并存储用户权限等。

现在,我想使用基于 API 密钥的身份验证(通过请求标头中的 api-key)向第三方消费者公开同一组 API。 我开发了一个自定义身份验证处理程序,如下所示。

using Microsoft.AspNetCore.Authentication;

namespace Management.Deployment.Securities.Authentication

  public class ApiKeyAuthenticationSchemeOptions : AuthenticationSchemeOptions
  

  



namespace Management.Deployment.Securities.Authentication

  public static class ApiKeyAuthenticationDefaults
  
    public static readonly string AuthenticationScheme = "ApiKey";
    public static readonly string DisplayName = "ApiKey Authentication Scheme";
  

ApiKeyAuthenticationHandler 定义如下,直截了当,如果请求标头包含有效的 api 密钥,则添加权限声明(分配给 api 密钥)并将身份验证标记为成功,否则失败。

using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Management.Securities.Authorization;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;

namespace Management.Deployment.Securities.Authentication

  public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationSchemeOptions>
  
    private const string APIKEY_NAME = "x-api-key";
    private const string APIKEY_VALUE = "sdflasuowerposaddfsadf1121234kjdsflkj";

    public ApiKeyAuthenticationHandler(IOptionsMonitor<ApiKeyAuthenticationSchemeOptions> options,
                                       ILoggerFactory logger,
                                       UrlEncoder encoder,
                                       ISystemClock clock) : base(options, logger, encoder, clock)
    

    

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    
      string extractedApiKey = Request.Headers[APIKEY_NAME];

      if (!APIKEY_VALUE.Equals(extractedApiKey))
      
        return Task.FromResult(AuthenticateResult.Fail("Unauthorized client."));
      

      var claims = new[]
      
        new Claim("Permissions", "23")
      ;

      var claimsIdentity = new ClaimsIdentity(claims, nameof(ApiKeyAuthenticationHandler));
      var authenticationTicket = new AuthenticationTicket(new ClaimsPrincipal(claimsIdentity), Scheme.Name);

      return Task.FromResult(AuthenticateResult.Success(authenticationTicket));

    
  

我还定义了 ApiKeyAuthenticationExtensions 如下。

using Microsoft.AspNetCore.Authentication;
using Management.Deployment.Securities.Authentication;
using System;

namespace Microsoft.Extensions.DependencyInjection

  public static class ApiKeyAuthenticationExtensions
  
    public static AuthenticationBuilder AddApiKey(this AuthenticationBuilder builder)
    
      return builder.AddScheme<ApiKeyAuthenticationSchemeOptions, ApiKeyAuthenticationHandler>(ApiKeyAuthenticationDefaults.AuthenticationScheme, ApiKeyAuthenticationDefaults.DisplayName, x =>  );
    

    public static AuthenticationBuilder AddApiKey(this AuthenticationBuilder builder, Action<ApiKeyAuthenticationSchemeOptions> configureOptions)
    
      return builder.AddScheme<ApiKeyAuthenticationSchemeOptions, ApiKeyAuthenticationHandler>(ApiKeyAuthenticationDefaults.AuthenticationScheme, ApiKeyAuthenticationDefaults.DisplayName, configureOptions);
    
  

Startup.cs 中 ConfigureServices() 的略读版本在这里。请注意我使用了 ForwardDefaultSelector。

public void ConfigureServices(IServiceCollection services)
        
            IAuthCookieValidate cookieEvent = new AuthCookieValidate();

            services.AddAuthentication(options =>
            
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            )
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            
                options.Cookie.Name = ".Mgnt.AspNetCore.Cookies";
                options.ExpireTimeSpan = TimeSpan.FromDays(1);
                options.Events = new CookieAuthenticationEvents
                
                    OnRedirectToAccessDenied = context =>
                    
                        context.Response.StatusCode = 403;
                        return Task.FromResult(0);
                    ,
                    OnRedirectToLogin = context =>
                    
                        context.Response.StatusCode = 401;
                        return Task.FromResult(0);
                    ,
                    OnValidatePrincipal = cookieEvent.ValidateAsync
                ;
                options.ForwardDefaultSelector = context =>
                
                    return context.Request.Headers.ContainsKey(ApiConstants.APIKEY_NAME) ? ApiKeyAuthenticationDefaults.AuthenticationScheme : CookieAuthenticationDefaults.AuthenticationScheme;
                ;
                options.Cookie.HttpOnly = true;
                options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
            )
            .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => Configuration.Bind(OpenIdConnectDefaults.AuthenticationScheme, options))
            .AddApiKey();

            services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
            
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Scope.Add("email");
            );
            

            services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();

        

配置方法如下。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            

            app.UseHsts();
            app.Use((context, next) =>
            
                context.Request.Scheme = "https";
                return next();
            );

            app.UseRouting();

            app.UseAuthentication();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllers();
            );
           

当我在请求标头中发送正确的 apikey 时,自定义处理程序将返回成功作为身份验证结果,并进一步处理请求。

但如果传递了错误的 api 密钥,它不会返回身份验证失败消息 - “未经授权的客户端。”。而是进一步处理请求并发送附加的响应。

为解决此问题需要进行哪些更改,以便 api 返回身份验证失败消息 - “未经授权的客户端”。并停止进一步处理请求?

【问题讨论】:

【参考方案1】:

如果您打算使用 apikeys,那么您只能靠自己,并且(据我所知)没有内置的对 API-keys 的直接支持。但是,内置了对基于 JWT 的访问令牌的支持,我建议您也将它用于想要访问您的 api 的外部第三方。也许使用客户端凭据流。

如需帮助,请参阅http://codingsonata.com/secure-asp-net-core-web-api-using-api-key-authentication/

我还认为您应该配置并让授权处理程序负责决定谁可以访问服务。

见Policy-based authorization in ASP.NET Core

【讨论】:

我已经用实施细节更新了我的问题。请看一看。 查看我的更新答案

即使在 asp.net core 5.0 中提供了不记名令牌,也会返回 401 [关闭]

...】:2021-04-2109:01:11【问题描述】:所以我正在尝试为我的webapi应用程序设置身份验证。现在我只是在乱搞并试图让我的授权端点工作承载令牌,但即使使用令牌我仍然得到401。我想我已经尝试了所 查看详情

如何在 Asp.Net Core 3.0 WebAPI 中启用 CORS

】如何在Asp.NetCore3.0WebAPI中启用CORS【英文标题】:HowtoenableCORSinAsp.NetCore3.0WebAPI【发布时间】:2020-09-0721:49:39【问题描述】:我想通过Asp.NetCore3.0API项目启用CORS。这是生成的基本Asp.NetCoreApi模板。模板中的所有内容都是默认设置,... 查看详情

在 ASP.Net Core 5 WebAPI 中启用 CORS

】在ASP.NetCore5WebAPI中启用CORS【英文标题】:EnableCORSinASP.NetCore5WebAPI【发布时间】:2021-04-0906:31:40【问题描述】:有数以百万计的文章和问题与此问题相关,但我找不到我的代码有什么问题。我有Startup、StartupProduction和StartupDevelop... 查看详情

在 ASP.NET Core WebAPI 中获取 OData 计数

】在ASP.NETCoreWebAPI中获取OData计数【英文标题】:GettingODataCountinASP.NETCoreWebAPI【发布时间】:2020-03-0908:39:15【问题描述】:使用HassanHabib的SuperchargingASP.NETCoreAPIwithOData博客文章中的示例代码,我可以使用$count=true的OData查询获取记... 查看详情

获取 ASP .Net Core WebAPI 中的所有身份角色

】获取ASP.NetCoreWebAPI中的所有身份角色【英文标题】:GetallIdentityrolesinASP.NetCoreWebAPI【发布时间】:2021-10-1002:54:22【问题描述】:我的任务是获取数据库中的所有身份角色。我使用下面的代码来获取所有角色。在Asp.Net核心WebAPI中U... 查看详情

如何在 ASP.net Core WebAPI 中启用 CORS

】如何在ASP.netCoreWebAPI中启用CORS【英文标题】:HowtoenableCORSinASP.netCoreWebAPI【发布时间】:2021-12-3009:59:00【问题描述】:我要做什么我有一个托管在Azure免费计划上的后端ASP.NetCoreWebAPI(源代码:https://github.com/killerrin/Portfolio-Backend... 查看详情

如何在 Asp Net Core Web App(不是 WebAPI)中存储令牌

】如何在AspNetCoreWebApp(不是WebAPI)中存储令牌【英文标题】:HowtostoretokeninAspNetCoreWebApp(notWebAPI)【发布时间】:2020-08-0920:03:09【问题描述】:我想在Asp.NetCoreWebApp(不是WebAPI)中使用JWT令牌对用户进行身份验证。如何存储JWT令牌... 查看详情

在 ASP.NET Core WebApi 中处理多个租户

】在ASP.NETCoreWebApi中处理多个租户【英文标题】:HandlingmultipletenantsinASP.NETCoreWebApi【发布时间】:2022-01-0816:41:21【问题描述】:我开发了.NETCoreWebApi应用程序,并且有几个不同的客户使用具有不同配置的同一个应用程序。(应用... 查看详情

ASP.NET Core 2.2 WebAPI 405 方法不允许

】ASP.NETCore2.2WebAPI405方法不允许【英文标题】:ASP.NETCore2.2WebAPI405MethodNotAllowed【发布时间】:2019-09-2219:23:12【问题描述】:设置Windows10VisualStudio2017专业版ASP.NetCore2.2我要做什么针对我的WebAPI中使用PATCH动词的控制器方法运行集成... 查看详情

在 Asp.Net Core 5.0 中注册 HttpClient 时注入 ILogger

】在Asp.NetCore5.0中注册HttpClient时注入ILogger【英文标题】:InjectILoggerwhenregisteringHttpClientinAsp.NetCore5.0【发布时间】:2021-12-1721:14:06【问题描述】:在Asp.NetCore中注册自定义服务时,例如:services.AddScoped<ISomeService,SomeService>();然... 查看详情

检查用户是不是存在于 ASP.NET Core WebAPI JWT 身份验证中

】检查用户是不是存在于ASP.NETCoreWebAPIJWT身份验证中【英文标题】:CheckifuserexistsinASP.NETCoreWebAPIJWTAuthentication检查用户是否存在于ASP.NETCoreWebAPIJWT身份验证中【发布时间】:2020-08-0520:54:39【问题描述】:我已成功在我的WebAPI中设置... 查看详情

ASP.NET CORE 5.0 Identity 显示当前登录用户

】ASP.NETCORE5.0Identity显示当前登录用户【英文标题】:ASP.NETCORE5.0IdentityDisplaycurrentloggedinuser【发布时间】:2021-03-0309:26:36【问题描述】:我试图在IndexPage中显示哪个用户提交ticket。在我的模型中,我添加了属性publicint?UserIdget;set;pu... 查看详情

Asp.Net Core 5.0 中 EntityState.Detached 的空异常 [关闭]

】Asp.NetCore5.0中EntityState.Detached的空异常[关闭]【英文标题】:NullExceptiononEntityState.DetachedinAsp.NetCore5.0[closed]【发布时间】:2021-10-0106:22:20【问题描述】:我有一个用户个人资料页面,用户可以更新它自己的信息。当我尝试更新时... 查看详情

无法在 ASP.NET Core 5.0 下的 IIS 中托管 CoreWcf

】无法在ASP.NETCore5.0下的IIS中托管CoreWcf【英文标题】:CannothostCoreWcfinIISunderASP.NETCore5.0【发布时间】:2021-09-1606:02:15【问题描述】:我尝试将我的WCFWeb服务从.NetFramework4.7.1迁移到.Net5.0。我使用nuggetCoreWcf并尝试在IIS上运行它。阅... 查看详情

使用 JWT 令牌的 ASP.NET Core 网站到 WebApi 身份验证

】使用JWT令牌的ASP.NETCore网站到WebApi身份验证【英文标题】:ASP.NETCoreWebsitetoWebApiauthenticationusingJWTtoken【发布时间】:2019-07-1718:34:13【问题描述】:我正在开发一个ASP.NETCore2.2网站,用户需要登录然后使用它。我网站中的AccountContr... 查看详情

如何在 ASP.NET Core 5.0 中处理来自客户端的双重请求?

】如何在ASP.NETCore5.0中处理来自客户端的双重请求?【英文标题】:HowtohandledoublerequestsfromtheclientinASP.NETCore5.0?【发布时间】:2021-12-1309:13:22【问题描述】:客户端应用程序对服务器上的单个资源进行双重查询。第一帧没有授权头... 查看详情

如何按照存储库模式在 Asp.Net Core 5.0 项目上实现 .Net Core Identity?

】如何按照存储库模式在Asp.NetCore5.0项目上实现.NetCoreIdentity?【英文标题】:HowToImplement.NetCoreIdentityonAsp.NetCore5.0ProjectFollowingRepositoryPattern?【发布时间】:2021-09-0109:23:58【问题描述】:我正在研究.NetCore5.0技术,我目前的项目结... 查看详情

如何在无视图 WebAPI ASP.NET Core 应用程序中使用 [Authorize] 和防伪?

】如何在无视图WebAPIASP.NETCore应用程序中使用[Authorize]和防伪?【英文标题】:Howtouse[Authorize]andantiforgeryinaView-lessWebAPIASP.NETCoreapp?【发布时间】:2018-08-1100:34:33【问题描述】:当我无法保证客户端将使用什么平台时,我无法在严... 查看详情