代码之家  ›  专栏  ›  技术社区  ›  Matthew Warr

.NET Core 2.0->5.0 API身份验证-多个方案

  •  0
  • Matthew Warr  · 技术社区  · 4 年前

    我有一本书。NET核心(当时是2.0,现在逐步升级到5)使用MVC和标准标识的web应用程序。它有一个基于web的登录/后端UI。升级过程在这方面做得很好,一切都正常运行。

    然而,我也有一组WebAPI控制器,使用JWT承载令牌,这些控制器已经停止工作,现在都抛出401错误。

    我很确定我需要以某种方式注册额外的授权方案,但我不确定如何注册。

    下面是控制器的工作原理

        [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
        [Route("api/[controller]")]
    

    以下是我创业公司的摘录。反恐精英

    public void ConfigureServices(IServiceCollection services)
            {
                services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("TechsportiseDB")));
                //options.UseInMemoryDatabase("Techsportise"));
    
                services.AddIdentity<ApplicationUser, IdentityRole>(config =>
                    {
                        config.SignIn.RequireConfirmedEmail = true;
                    })
                    .AddEntityFrameworkStores<ApplicationDbContext>()
                    .AddDefaultTokenProviders();
    
                services.Configure<IdentityOptions>(options =>
                {
                    // Omitted
                });
    
                services.ConfigureApplicationCookie(options =>
                {
                    // Cookie settings
                    options.Cookie.HttpOnly = true;
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                    options.SlidingExpiration = true;
                });
    
               
                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Techsportise API", Version = "v1" });
                    c.OperationFilter<AddRequiredHeaderParameter>();
                    var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "TechsportiseOnline.xml");
                    c.IncludeXmlComments(filePath);
                });
    
                services.Configure<JWTSettings>(Configuration.GetSection("JWTSettings"));
    
                services.AddAuthentication()
                    .AddCookie()
                    .AddJwtBearer(options =>
                    {
                        options.RequireHttpsMetadata = false;
                        options.IncludeErrorDetails = true;
    
                        var secretKey = Configuration.GetSection("JWTSettings:SecretKey").Value;
                        var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
    
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
    
                            ValidateIssuer = true,
                            ValidIssuer = Configuration.GetSection("JWTSettings:Issuer").Value,
                            ValidateAudience = true,
                            ValidAudience = Configuration.GetSection("JWTSettings:Audience").Value,
                            ValidateIssuerSigningKey = true,
                            IssuerSigningKey = signingKey,
    
                        };
                        
                    });
    
    
                services.AddAuthorization();
               
    
                services.AddMvcCore(option => option.EnableEndpointRouting = false)
                    .AddViewLocalization(
                        LanguageViewLocationExpanderFormat.Suffix,
                        opts => { opts.ResourcesPath = "Resources"; })
                    .AddDataAnnotationsLocalization()
                    .AddApiExplorer();
    
    
                services.AddAntiforgery();
    
                var skipSSL = Configuration.GetValue<bool>("LocalTest:skipSSL");
    
                // requires using Microsoft.AspNetCore.Mvc;
                services.Configure<MvcOptions>(options =>
                {
                    // Set LocalTest:skipSSL to true to skip SSL requrement in 
                    // debug mode. This is useful when not using Visual Studio.
                    if (!skipSSL)
                    {
                        options.Filters.Add(new RequireHttpsAttribute());
                    }
                });
    
                services.AddSingleton<SharedViewLocalizer>();
                services.AddSingleton<SharedViewHtmlLocalizer>();
    
                services.AddControllersWithViews();
    
                
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
    
                if (env.EnvironmentName == "Development")
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                // Enable middleware to serve generated Swagger as a JSON endpoint.
                app.UseSwagger();
    
                // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
                app.UseSwaggerUI(c =>
                {
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Techsportise API V1");
                });
    
    
                app.UseDefaultFiles();
                app.UseStaticFiles();
    
              
                app.UseAuthentication();
                app.UseAuthorization();
    
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
        }
    
    0 回复  |  直到 4 年前
        1
  •  0
  •   Gordon Khanh Ng.    4 年前

    如果你能理解错误的原因可能会更好,所以我会在这里解释一下。

    我们都使用 app.UseAuthentication(); in-out startup类,它的幕后流程如下 this .

    在上述配置中,您提供了中间件2方案来进行处理

    services.AddAuthentication()
                    .AddCookie()
                    .AddJwtBearer(options =>
                    {
                        options.RequireHttpsMetadata = false;
                        options.IncludeErrorDetails = true;
    
                        var secretKey = Configuration.GetSection("JWTSettings:SecretKey").Value;
                        var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
    
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
    
                            ValidateIssuer = true,
                            ValidIssuer = Configuration.GetSection("JWTSettings:Issuer").Value,
                            ValidateAudience = true,
                            ValidAudience = Configuration.GetSection("JWTSettings:Audience").Value,
                            ValidateIssuerSigningKey = true,
                            IssuerSigningKey = signingKey,
    
                        };
                        
                    });
    

    第一个是 CookieAuthenticationDefaults.AuthenticationScheme 第二个是 JwtBearerDefaults.AuthenticationScheme . 然后他们都得到了execute(我知道你指出了方案,但你没有设置默认方案,所以 Schemes.GetDefaultAuthenticateSchemeAsync() 将返回可能不是我们想要的东西)。

    解决方案:使用默认方案,并提出一些逻辑来将管道转发给正确的处理器!

    services.AddAuthentication(opts =>
                    {
                        opts.DefaultScheme = "multi-scheme-election";
                        opts.DefaultChallengeScheme = "multi-scheme-election";
                    })
                    .AddCookie()
                    .AddJwtBearer(options =>
                    {
                        options.RequireHttpsMetadata = false;
                        options.IncludeErrorDetails = true;
    
                        var secretKey = configuration.GetSection("JWTSettings:SecretKey").Value;
                        var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
    
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
    
                            ValidateIssuer = true,
                            ValidIssuer = configuration.GetSection("JWTSettings:Issuer").Value,
                            ValidateAudience = true,
                            ValidAudience = configuration.GetSection("JWTSettings:Audience").Value,
                            ValidateIssuerSigningKey = true,
                            IssuerSigningKey = signingKey
                        };
                    })
                    .AddPolicyScheme("multi-scheme-election", "Your Election scheme processor here",
                        cfgOpts => cfgOpts.ForwardDefaultSelector = ctx =>
                            ctx.Request.Headers.ContainsKey("Authorization")
                                ? JwtBearerDefaults.AuthenticationScheme
                                : CookieAuthenticationDefaults.AuthenticationScheme);
    

    好了,试试看

    [HttpGet("TestAuthentication")]
    [Authorize] // No need to specify the scheme here, the default policy will take us the right one
    public IActionResult TestAuthentication()
    {
        return Ok("Authenticated!");
    }
    

    P/s:我现在也在用这个。

    推荐文章