C# Azure B2C//IDX10500的ASP.NET Core 2 Jwt身份验证:签名验证失败。没有提供安全密钥来验证签名

C# Azure B2C//IDX10500的ASP.NET Core 2 Jwt身份验证:签名验证失败。没有提供安全密钥来验证签名,c#,jwt,azure-ad-b2c,asp.net-core-2.0,msal,C#,Jwt,Azure Ad B2c,Asp.net Core 2.0,Msal,我面临Jwt身份验证的问题 我有一个ASP.NET Core 2 WepApi,它也为我的SPA应用程序(它是一个Vue应用程序)提供服务。SPA应用程序通过Microsoft的MSAL.js库从Azure B2C获取令牌 当我点击需要授权的WebApi时,出现以下错误: info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[1] Failed to validate the token [MyTok

我面临Jwt身份验证的问题

我有一个ASP.NET Core 2 WepApi,它也为我的SPA应用程序(它是一个Vue应用程序)提供服务。SPA应用程序通过Microsoft的MSAL.js库从Azure B2C获取令牌

当我点击需要授权的WebApi时,出现以下错误:

info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[1]
      Failed to validate the token [MyTokenHere]
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__6.MoveNext()
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[7]
      Bearer was not authenticated. Failure message: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
我在这里提供的示例应用程序(及其tanant)中面临同样的问题

这是我的Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using VueTemplate.SignalR;

namespace VueTemplate
{
    public class Startup
    {
        public string Authority { get; set; } = "https://login.microsoftonline.com/tfp/[MyB2CTenant]/[MyPolicy]/v2.0/";

        public string ClientId { get; set; } = [MyApplicationId];


        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddSignalR();
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options => new JwtBearerOptions() {
                Authority = Authority,
                Audience = ClientId,
                Events = new JwtBearerEvents() { OnAuthenticationFailed = AuthenticationFailed,  }
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions() {
                    HotModuleReplacement = true
                });
            }
            else {
                app.UseExceptionHandler("/Home/Error"); // TODO Create Error page
            }

            app.UseAuthentication();

            app.UseStaticFiles();

            app.UseSignalR(routes => {
                routes.MapHub<ChatHub>("Hub/Chat");
            });

            app.UseMvc(routes => {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}"
                );

                routes.MapSpaFallbackRoute(
                    name: "spa-fallback",
                    defaults: new { controller = "Home", action = "Index" }
                );
            });
        }

        private Task AuthenticationFailed(AuthenticationFailedContext arg)
        {
            // For debugging purposes only!
            var s = $"AuthenticationFailed: {arg.Exception.Message}";
            arg.Response.ContentLength = s.Length;
            arg.Response.Body.Write(Encoding.UTF8.GetBytes(s), 0, s.Length);
            return Task.FromResult(0);
        }
    }
}

有什么想法吗?我必须提供安全密钥吗?我在Azure B2C的哪里可以找到它?

我已经找到了解决问题的方法

配置
AddJwtBearer()
方法的正确方法是使用已经提供的options对象,而不是创建新对象

坏的:


我已经找到了解决我问题的办法

配置
AddJwtBearer()
方法的正确方法是使用已经提供的options对象,而不是创建新对象

坏的:


你试过这个吗?我想知道你是否可以让你的水疗工作与后端样本。是的,我已经尝试了这个例子。我在问题中已经提到了这一点。无论是否有SPA,我都无法获得样本。该示例是否适用于您?您不必提供安全密钥。库动态获取密钥并执行验证。哎呀,我的错。我现在明白了。让我自己试试。一定要用2.0版本。有两个分支。我真的很感激你能亲自尝试!你试过这个吗?我想知道你是否可以让你的水疗工作与后端样本。是的,我已经尝试了这个例子。我在问题中已经提到了这一点。无论是否有SPA,我都无法获得样本。该示例是否适用于您?您不必提供安全密钥。库动态获取密钥并执行验证。哎呀,我的错。我现在明白了。让我自己试试。一定要用2.0版本。有两个分支。我真的很感激你能亲自尝试!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using VueTemplate.SignalR;

namespace VueTemplate
{
    public class Startup
    {
        public string Authority { get; set; } = "https://login.microsoftonline.com/tfp/[MyB2CTenant]/[MyPolicy]/v2.0/";

        public string ClientId { get; set; } = [MyApplicationId];


        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddSignalR();
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options => new JwtBearerOptions() {
                Authority = Authority,
                Audience = ClientId,
                Events = new JwtBearerEvents() { OnAuthenticationFailed = AuthenticationFailed,  }
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions() {
                    HotModuleReplacement = true
                });
            }
            else {
                app.UseExceptionHandler("/Home/Error"); // TODO Create Error page
            }

            app.UseAuthentication();

            app.UseStaticFiles();

            app.UseSignalR(routes => {
                routes.MapHub<ChatHub>("Hub/Chat");
            });

            app.UseMvc(routes => {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}"
                );

                routes.MapSpaFallbackRoute(
                    name: "spa-fallback",
                    defaults: new { controller = "Home", action = "Index" }
                );
            });
        }

        private Task AuthenticationFailed(AuthenticationFailedContext arg)
        {
            // For debugging purposes only!
            var s = $"AuthenticationFailed: {arg.Exception.Message}";
            arg.Response.ContentLength = s.Length;
            arg.Response.Body.Write(Encoding.UTF8.GetBytes(s), 0, s.Length);
            return Task.FromResult(0);
        }
    }
}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace VueTemplate.Controllers
{
    [Authorize]
    [Route("api/[controller]/")]
    public class ValuesController : Controller
    {
        [HttpGet]
        public IActionResult Get() {
            return Ok(new int[] { 1, 2, 3, 4 });
        }
    }
}
.AddJwtBearer(option => new JwtBearerOptions // <--- Evil 
                {
                    Authority = string.Format("https://login.microsoftonline.com/tfp/{0}/{1}/v2.0/",
                    Configuration["Authentication:AzureAd:Tenant"], Configuration["Authentication:AzureAd:Policy"]),
                    Audience = Configuration["Authentication:AzureAd:ClientId"],
                    Events = new JwtBearerEvents
                    {
                        OnAuthenticationFailed = AuthenticationFailed
                    },
                });
.AddJwtBearer(options => {
                    options.Authority = string.Format("https://login.microsoftonline.com/tfp/{0}/{1}/v2.0/", Configuration["Authentication:AzureAd:Tenant"], Configuration["Authentication:AzureAd:Policy"]);
                    options.Audience = Configuration["Authentication:AzureAd:ClientId"];
                    options.Events = new JwtBearerEvents {
                        OnAuthenticationFailed = AuthenticationFailed
                    };
                });