asp.net core 支持多中Authentication,通过header头区分jwt

-- asp.net core 支持多中Authentication,通过header头区分jwttoken,走不不同的TokenValidationParameters
【官网】:https://docs.microsoft.com/en-us/aspnet/core/security/?view=aspnetcore-5.0

应用场景

在asp.net core 的应用中,启用jwttoken后,往往有些场景需要我们启用多种验证方式,比如我们api自身有一种默认身份验证,同时针对合作伙伴也需要一种。 比如有时合作伙伴和我们的api应用有公钥/私钥的配置和校验,这时就需要专门有一种方案识别采用哪一种jwttoken的验证参数。

基础资源

本文示例为asp.net core 3.1 (建议>=3.1)

使用须知

具体应用需要结合实际业务场景来决定. 无论采取何种方式,都需要充分测试: 匿名api, 无特殊头的jwttoken验证,有特殊头的jwttoken, 非匿名api的无凭据访问等场景。

配置步骤

[注]关于如何在asp.net core中启用jwttoken验证,请自行百度,这里主要介绍一下多种Authentication的处理.

步骤1: 添加多个Authentication Schema。


      services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
       .AddJwtBearer(options =>
       {
           options.TokenValidationParameters = new TokenValidationParameters()
           {
               ValidateLifetime = true,
               ValidateAudience = true,
               ValidateIssuer = true,
               ValidIssuer = _appSetting.Default.Issuer,
               ValidAudience = _appSetting.Default.Audience,
               ValidateIssuerSigningKey = true,
               IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSetting.Default.SecurityKey))
           };
       })
       .AddJwtBearer(AuthSchema.Partner, options =>
       {
           options.TokenValidationParameters = new TokenValidationParameters()
           {
               ValidateLifetime = true,
               ValidateAudience = true,
               ValidateIssuer = true,
               ValidIssuer = _appSetting.Partner.Issuer,
               ValidAudience = _appSetting.Partner.Audience,
               ValidateIssuerSigningKey = true,
               IssuerSigningKey = new  ECDsaSecurityKey(EcdsaUtils.LoadPublicKey(_appSetting.Partner.SecurityKey))
          };
       });

步骤2: 添加一个自定义的AuthorizationFilter特性。


using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ConfigLab.Dnc.Tester.Controllers.Share.Commons
{

    public class BaseAthenticationAttr: Attribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            string reqAuthSchema = context.HttpContext?.Request?.Headers["AuthSchema"];
            var realAuthSchema = AuthSchema.GetAuthSchema(reqAuthSchema);
            var res = context.HttpContext.AuthenticateAsync(realAuthSchema).Result;
            if (!res.Succeeded&&!HasAllowAnonymous(context))//身份验证失败
            {
                context.Result = new ObjectResult(res?.Failure?.Message) { StatusCode = 401 };
            }
        }
 private bool HasAllowAnonymous(AuthorizationFilterContext context)
 {
     var filters = context.Filters;
     for (var i = 0; i < filters.Count; i++)
     {
         if (filters[i] is IAllowAnonymousFilter)
         {
             return true;
         }
     }
     // When doing endpoint routing, MVC does not add AllowAnonymousFilters for AllowAnonymousAttributes that
     // were discovered on controllers and actions. To maintain compat with 2.x,
     // we‘ll check for the presence of IAllowAnonymous in endpoint metadata.
     var endpoint = context.HttpContext.GetEndpoint();
     if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
     {
         return true;
     }
     return false;
 } 
}
    public static class AuthSchema
    {
        public  static readonly List<string> ListAuthSchema = new List<string>();
        static AuthSchema()
        {
            ListAuthSchema.AddRange(new string[] {Partner });
        }
        public static string GetAuthSchema(string authSchema)
        {
            if (ListAuthSchema.Contains(authSchema))
                return authSchema;
            return JwtBearerDefaults.AuthenticationScheme;
        }
        public const string Partner = "Partner";
    }
}

步骤3:应用到controller中.


    [BaseAthenticationAttr]
    [Route("api/[controller]")]
    [ApiController]
    public class ApiBaseController : ControllerBase
    {

    }



---------------------------------------至此,支持多种Authentication的处理已经完成,下面开始介绍调用时的处理---------------------

http请求我们这里先不介绍参数,请求方式等,只关注与jwttoken验证相关的。


1)默认的调用请求Header头示例.

Authorization:  Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYXV0aC5jb25maWcubmV0LmNuIiwic3ViIjoidXNlcl90ZXN0IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvZGF0ZW9mYmlydGgiOiIxNjAyMDk4MDg4IiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9leHBpcmF0aW9uIjoiMTYwMjA5ODEwOCIsIm5iZiI6MTYwMjA5ODA4OCwiZXhwIjoxNjAyMDk4MTA4LCJpc3MiOiJhdXRoLmNvbmZpZy5uZXQuY24iLCJhdWQiOiJjb25maWcubmV0LmNuIn0.7PGl0u9M7MQxtA182DVgnMbz42E_3IAbQhBISUtiYCw


2)合作方的调用请求Header头。


AuthSchema:Partner   //这里就是指定走哪一个jwttoken验证的


Authorization:  Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYXV0aC5jb25maWcubmV0LmNuIiwic3ViIjoidXNlcl90ZXN0IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvZGF0ZW9mYmlydGgiOiIxNjAyMDk4MDg4IiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9leHBpcmF0aW9uIjoiMTYwMjA5ODEwOCIsIm5iZiI6MTYwMjA5ODA4OCwiZXhwIjoxNjAyMDk4MTA4LCJpc3MiOiJhdXRoLmNvbmZpZy5uZXQuY24iLCJhdWQiOiJjb25maWcubmV0LmNuIn0.7PGl0u9M7MQxtA182DVgnMbz42E_3IAbQhBISUtiYCw

常见问题

快速入门

参考资料