2017-10-04 14 views
0

Jwt 인증에 문제가 있습니다.Azure B2C // IDX10500을 사용하는 ASP.NET Core 2 Jwt Auth : 서명 유효성 검사가 실패했습니다. 서명을 확인하기위한 보안 키가 제공되지 않았습니다.

SPA App (Vue-App) 서비스도 제공하는 ASP.NET Core 2 WepApi가 있습니다. SPA App은 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. 

을 나는 401

GET http://localhost:51420/api/values 401 (Unauthorized) 

내가 샘플과 똑같은 문제에 직면 얻을 응용 프로그램 (자신의 tanant로) 여기 An ASP.NET Core web API with Azure AD B2C를 제공 여기

내 Startup.cs

입니다 691,363,210
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); 
     } 
    } 
} 

ValuesController.cs

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 }); 
     } 
    } 
} 

어떤 생각이? 보안 키를 제공해야합니까? Azure B2C에서 어디에서 찾을 수 있습니까?

+0

당신이 [예제]를 해봤 (https://github.com/Azure-Samples/active-directory-b2c-dotnetcore-webapi /blob/master/B2C-WebApi/Startup.cs#LC52)? SPA가 백엔드 샘플로 작동 할 수 있는지 궁금합니다. – spottedmahn

+0

예이 예제를 시도했습니다. 나는 이미 내 질문에 그것을 언급했다. 나는 샘플을 내 SPA의 유무와 상관없이 사용할 수 없다. 샘플이 당신을 위해 작동합니까? – VSDekar

+0

보안 키를 제공 할 필요가 없습니다. 라이브러리는 키를 동적으로 가져 와서 유효성 검사를 수행합니다. [참고 1] (https://stackoverflow.com/questions/45623178/wheres-the-key-for-my-azure-ad-b2c-token). [참조 2 - 토큰 유효성 검사] (https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-tokens#token-validation) – spottedmahn

답변

3

내 문제에 대한 해결책을 찾았습니다.

AddJwtBearer() 메서드를 구성하는 올바른 방법은 이미 제공된 옵션 개체를 사용하고 새 개체를 만들지 않는 것입니다.

나쁜 :

.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 
        }; 
       });