2016-03-04 97 views
2

我想了解所有關於JWT令牌在Asp.Net核心的東西。出血後的工作與大量的missunderstandings我卡住了。我的任務是使WebApi服務器具有兩個控制器(受保護而不受保護)。我應該從服務器授予令牌並能夠獲得受保護的資源。當我運行服務器並嘗試從郵遞員獲取受保護的資源時,一切似乎都很順利。但是當我在我的角度做同樣的事情時,從另一個領域我有奇怪的事情。我可以得到無保護資源,我不能與這樣的錯誤得到保護資源:Asp.Net核心,智威湯遜和OpenIdConnectServer

XMLHttpRequest cannot load http://localhost:10450/api/prvalues. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:10377' is therefore not allowed access.

要清楚我告訴我所有的attemts。我project.json看起來像

"dependencies": { 
    "AspNet.Security.OpenIdConnect.Server": "1.0.0-beta4", 
    "EntityFramework.Core": "7.0.0-rc1-final", 
    "EntityFramework.InMemory": "7.0.0-rc1-final", 
    "Microsoft.AspNet.Authentication.JwtBearer": "1.0.0-rc1-final", 
    "Microsoft.AspNet.Diagnostics": "1.0.0-rc1-final", 
    "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-rc1-final", 
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final", 
    "Microsoft.AspNet.Mvc": "6.0.0-rc1-final", 
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final", 
    "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final", 
    "Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final", 
    "Microsoft.Extensions.Logging": "1.0.0-rc1-final", 
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final", 
    "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final", 
    "NWebsec.Middleware": "1.0.0-gamma-39", 
    "Microsoft.AspNet.Mvc.Cors": "6.0.0-rc1-final", 
    "Microsoft.AspNet.Cors": "6.0.0-rc1-final" 
}, 

Startup.ConfigureServices()看起來像

公共無效ConfigureServices(IServiceCollection服務) {

 services.AddCors(options => 
     { 
      options.AddPolicy("AllowAllOrigins", 
        builder => 
        { 
         builder.AllowAnyOrigin(); 
         builder.AllowAnyHeader(); 
        }); 
     }); 

     services.AddEntityFramework() 
      .AddInMemoryDatabase() 
      .AddDbContext<ApplicationDbContext<ApplicationUser, Application, IdentityRole, string>>(options => { 
       options.UseInMemoryDatabase(); 
      }); 
     services.AddScoped<IAuthStore<ApplicationUser,Application>, AuthStore<ApplicationUser, Application, IdentityRole, 
      ApplicationDbContext<ApplicationUser, Application, IdentityRole, string>, string>>(); 
     services.AddScoped<AuthManager<ApplicationUser, Application>>(); 
     services.AddIdentity<ApplicationUser, IdentityRole>(options => 
     { 
      options.Password = new PasswordOptions() 
      { 
       RequiredLength = 1, 
       RequireDigit = false, 
       RequireLowercase = false, 
       RequireUppercase = false, 
       RequireNonLetterOrDigit = false 

      }; 
     }).AddEntityFrameworkStores<ApplicationDbContext<ApplicationUser, Application, IdentityRole, string>>().AddDefaultTokenProviders(); 
     services.AddAuthentication(); 

     // Add framework services. 

     services.AddCaching(); 
     services.AddMvc(); 
    } 

AuthManager和AuthStore從OpenIddict被盜。我會晚些時候給他們看。我Startup.Configure()樣子:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
    { 
     loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
     loggerFactory.AddDebug(); 
     app.UseCors("AllowAllOrigins"); 
     app.UseIISPlatformHandler(); 
     app.UseDeveloperExceptionPage(); 
     app.UseStaticFiles(); 

     // Create a new branch where the registered middleware will be executed only for API calls.    

     app.UseWhen(context => context.Request.Path.StartsWithSegments(new PathString("/api")), branch => 
     { 
      branch.UseJwtBearerAuthentication(options => 
      { 

       options.AutomaticAuthenticate = true; 
       options.AutomaticChallenge = true; 
       options.RequireHttpsMetadata = false; 
       // Thisi is test, if I uncomment this and SetResource in AuthorizationProvider everything works in postman 
       //options.Audience = "http://localhost:10450/"; 
       // My Angular client 
       options.Audience = "http://localhost:10377/"; 
       // My Api 
       options.Authority = "http://localhost:10450/"; 

      }); 
     }); 



     // Note: visit https://docs.nwebsec.com/en/4.2/nwebsec/Configuring-csp.html for more information. 
     app.UseCsp(options => options.DefaultSources(configuration => configuration.Self()) 
            .ImageSources(configuration => configuration.Self().CustomSources("data:")) 
            .ScriptSources(configuration => configuration.UnsafeInline()) 
            .StyleSources(configuration => configuration.Self().UnsafeInline())); 

     app.UseXContentTypeOptions(); 

     app.UseXfo(options => options.Deny()); 

     app.UseXXssProtection(options => options.EnabledWithBlockMode()); 

     app.UseOpenIdConnectServer(options => 
     { 

      options.Provider = new AuthorizationProvider(); 
      // Note: see AuthorizationController.cs for more 
      // information concerning ApplicationCanDisplayErrors. 
      options.ApplicationCanDisplayErrors = true; 
      options.AllowInsecureHttp = true; 
      options.AuthorizationEndpointPath = PathString.Empty; 
      options.TokenEndpointPath = "/token"; 
      // Note: by default, tokens are signed using dynamically-generated 
      // RSA keys but you can also use your own certificate: 
      // options.SigningCredentials.AddCertificate(certificate); 
     }); 

     app.UseMvc(); 
     var hasher = new PasswordHasher<Application>(); 
     using (var database = app.ApplicationServices.GetService<ApplicationDbContext<ApplicationUser, Application, IdentityRole, string>>()) 
     {    
      database.Applications.Add(new Application 
      { 
       Id = "myPublicClient", 
       DisplayName = "My client application", 
       Type = ApplicationTypes.Public 
      }); 
      database.Applications.Add(new Application 
      { 
       Id = "myConfidentialClient", 
       DisplayName = "My client application", 
       Secret = hasher.HashPassword(null, "secret_secret_secret"), 
       Type = ApplicationTypes.Confidential 
      }); 

      database.SaveChanges(); 
      CreateUser(app).Wait(); 
     }   
    } 

最後,我AthorizationProvider.GrantResourceOwnerCredentials()(我用AspNet.Security.OpenIdConnect.Server)是:

public override async Task GrantResourceOwnerCredentials(GrantResourceOwnerCredentialsContext context) 
    { 

     #region UserChecking 
     var manager = context.HttpContext.RequestServices.GetRequiredService<AuthManager<ApplicationUser, Application>>(); 

     var user = await manager.FindByNameAsync(context.UserName); 
     if (user == null) 
     { 
      context.Rejected(
       error: OpenIdConnectConstants.Errors.InvalidGrant, 
       description: "Invalid credentials."); 

      return; 
     } 

     // Ensure the user is not already locked out. 
     if (manager.SupportsUserLockout && await manager.IsLockedOutAsync(user)) 
     { 
      context.Rejected(
       error: OpenIdConnectConstants.Errors.InvalidGrant, 
       description: "Account locked out."); 

      return; 
     } 

     // Ensure the password is valid. 
     if (!await manager.CheckPasswordAsync(user, context.Password)) 
     { 
      context.Rejected(
       error: OpenIdConnectConstants.Errors.InvalidGrant, 
       description: "Invalid credentials."); 

      if (manager.SupportsUserLockout) 
      { 
       await manager.AccessFailedAsync(user); 

       // Ensure the user is not locked out. 
       if (await manager.IsLockedOutAsync(user)) 
       { 
        context.Rejected(
         error: OpenIdConnectConstants.Errors.InvalidGrant, 
         description: "Account locked out."); 
       } 
      } 

      return; 
     } 

     if (manager.SupportsUserLockout) 
     { 
      await manager.ResetAccessFailedCountAsync(user); 
     } 


     if (context.Request.ContainsScope(OpenIdConnectConstants.Scopes.Profile) && 
      !context.Request.ContainsScope(OpenIdConnectConstants.Scopes.Email) && 
      string.Equals(await manager.GetUserNameAsync(user), 
          await manager.GetEmailAsync(user), 
          StringComparison.OrdinalIgnoreCase)) 
     { 
      context.Rejected(
       error: OpenIdConnectConstants.Errors.InvalidRequest, 
       description: "The 'email' scope is required."); 

      return; 
     } 

     #endregion 

     var identity = await manager.CreateIdentityAsync(user, context.Request.GetScopes()); 

     var ticket = new AuthenticationTicket(
      new ClaimsPrincipal(identity), 
      new AuthenticationProperties(), 
      context.Options.AuthenticationScheme); 

     //ticket.SetResources(context.Request.GetResources()); 
     // When I tested with postman 
     //ticket.SetResources(new[] { "http://localhost:10450/" }); 
     ticket.SetResources(new[] { "http://localhost:10377" }); 
     ticket.SetScopes(context.Request.GetScopes()); 

     context.Validated(ticket); 


    } 

我已經表明的所有代碼,我認爲可能會導致問題。對不起,如果它長,但我不知道女巫部分導致問題。

訪問My protecetd資源(簡單裝飾的[Authorize])我使用這些虛擬代碼從我的角度客戶

$http.defaults.headers.common['Authorization'] = 'Bearer ' + 'token here'; 
return $http.get('http://localhost:10450/' + 'api/prvalues'); 

正如我所說的,我有這樣的要求CORS錯誤。但是,如果我試圖得到不受保護的資源(從控制器刪除[Authorize]屬性),一切正常。

+0

你有沒有嘗試使用'AllowCredentials()'和'AllowAnyMethod()'一起在github上的Cors例子中? https://github.com/aspnet/Mvc/blob/5b805bb12db3e47b380038cf6aa5d149f9f02421/test/WebSites/CorsWebSite/Startup.cs#L52-L60 – Tseng

+0

是的。它沒有效果 – Stalso

回答

1

我找到了解決方案。當我在我的AthorizationProvider.GrantResourceOwnerCredentials()中設置資源時,我設置了「http://localhost:10377」,但在UseJwtBearerAuthentication中間件中,我在權限選項(末尾包含斜槓)中設置了「http://localhost:10377/」。這是非常愚蠢的錯誤。