2017-09-04 1 views
5

Ich versuche, dieses Projekt https://github.com/asadsahi/AspNetCoreSpa von .net Core 1.1 auf 2.0 zu migrieren, aber ein Problem nach einer erfolgreichen Anmeldung. Nach dem Login ruft meine GET API e auf. G. zu https://localhost:44331/api/profile/test am Ende mit einer Weiterleitung (302) und ich weiß nicht warum. Ich habe einen Bearer Token erhalten und es sieht gut aus.ASP.NET Core 2 API-Aufruf wird umgeleitet (302)

Anforderungs-Header-Format: Berechtigung: Bearer [token]

[Route("api/[controller]")] 
public class ProfileController : BaseController 
{ 
    private readonly UserManager<ApplicationUser> _userManager; 
    private readonly ILogger _logger; 

    public ProfileController(ILoggerFactory loggerFactory, UserManager<ApplicationUser> userManager) 
    { 
     _logger = loggerFactory.CreateLogger<ProfileController>(); 
     _userManager = userManager; 
    } 

    [HttpGet("test")] 
    public async Task<IActionResult> Test() 
    { 
     return Json(ModelState.GetModelErrors()); 
    } 
} 

[Authorize] 
[ServiceFilter(typeof(ApiExceptionFilter))] 
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)] 
public class BaseController : Controller 
{ 
    public BaseController() 
    { 
    } 
} 

Startup.cs:

public void ConfigureServices(IServiceCollection services) 
    { 
     if (_hostingEnv.IsDevelopment()) 
     { 
      services.AddSslCertificate(_hostingEnv); 
     } 
     else 
     { 
      services.Configure<MvcOptions>(o => o.Filters.Add(new RequireHttpsAttribute())); 
     } 
     services.AddOptions(); 
     services.AddCors(); 
     services.AddLogging(); 
     services.AddResponseCompression(options => 
     { 
      options.MimeTypes = Helpers.DefaultMimeTypes; 
     }); 

     services.AddAuthentication(sharedOptions => 
     { 
      sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; 
      sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 
      sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 


     }).AddJwtBearer(cfg => 
     { 
      cfg.SaveToken = true; 
      cfg.TokenValidationParameters = new TokenValidationParameters 
      { 
       ValidIssuer = Configuration["Authentication:BearerTokens:Issuer"], 
       ValidAudience = Configuration["Authentication:BearerTokens:Audience"], 
       IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Authentication:BearerTokens:Key"])), 
       ValidateIssuerSigningKey = false, 
       ValidateLifetime = true, 
       ClockSkew = TimeSpan.Zero 
      }; 
      cfg.Events = new JwtBearerEvents 
      { 

       OnAuthenticationFailed = context => 
       { 
        var logger = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(JwtBearerEvents)); 
        logger.LogError("Authentication failed.", context.Exception); 
        return Task.CompletedTask; 
       }, 

       OnMessageReceived = context => 
       { 
        return Task.CompletedTask; 
       }, 
       OnChallenge = context => 
       { 
        var logger = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(JwtBearerEvents)); 
        logger.LogError("OnChallenge error", context.Error, context.ErrorDescription); 
        return Task.CompletedTask; 
       } 
      }; 
     }); 

     services.AddDbContext<ApplicationDbContext>(options => 
     { 
      string useSqLite = Startup.Configuration["Data:useSqLite"]; 
      if (useSqLite.ToLower() == "true") 
      { 
       options.UseSqlite(Startup.Configuration["Data:SqlLiteConnectionString"]); 
      } 
      else 
      { 
       options.UseSqlServer(Startup.Configuration["Data:SqlServerConnectionString"]); 
      } 
      options.UseOpenIddict(); 
     }); 


     services.AddIdentity<ApplicationUser, ApplicationRole>() 
      .AddEntityFrameworkStores<ApplicationDbContext>() 
      .AddDefaultTokenProviders(); 

     //services.ConfigureApplicationCookie(options => 
     //{ 

     // options.LoginPath = "/login"; 
     // options.Events.OnRedirectToLogin = context => 
     // { 
     //  if (context.Request.Path.StartsWithSegments("/api") && 
     //   context.Response.StatusCode == (int)HttpStatusCode.OK) 
     //  { 
     //   context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
     //  } 
     //  else 
     //  { 
     //   context.Response.Redirect(context.RedirectUri); 
     //  } 
     //  return Task.FromResult(0); 
     // }; 
     //}); 


     services.AddOAuthProviders(); 

     services.AddCustomOpenIddict(); 

     services.AddMemoryCache(); 

     services.RegisterCustomServices(); 

     services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); 

     services.AddCustomizedMvc(); 

     // Node services are to execute any arbitrary nodejs code from .net 
     services.AddNodeServices(); 

     services.AddSwaggerGen(c => 
     { 
      c.SwaggerDoc("v1", new Info { Title = "AspNetCoreSpa", Version = "v1" }); 
     }); 
    } 

public void Configure(IApplicationBuilder app) 
    { 
     app.AddDevMiddlewares(); 

     if (_hostingEnv.IsProduction()) 
     { 
      app.UseResponseCompression(); 
     } 

     app.SetupMigrations(); 

     app.UseXsrf(); 

     app.UseStaticFiles(); 

     app.UseAuthentication(); 

     app.UseMvc(routes => 
     { 
      // http://stackoverflow.com/questions/25982095/using-googleoauth2authenticationoptions-got-a-redirect-uri-mismatch-error 
      routes.MapRoute(name: "signin-google", template: "signin-google", defaults: new { controller = "Account", action = "ExternalLoginCallback" }); 

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

Meine IServiceCollection-Erweiterungen:

public static IServiceCollection AddCustomizedMvc(this IServiceCollection services) 
    { 
     services.AddMvc(options => 
     { 
      options.Filters.Add(typeof(ModelValidationFilter)); 
     }) 
     .AddJsonOptions(options => 
     { 
      options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 
     }); 

     return services; 
    } 

    public static IServiceCollection AddOAuthProviders(this IServiceCollection services) 
    { 
     services.AddAuthentication() 
      .AddFacebook(o => 
      { 
       o.AppId = Startup.Configuration["Authentication:Facebook:AppId"]; 
       o.AppSecret = Startup.Configuration["Authentication:Facebook:AppSecret"]; 
      }); 

     services.AddAuthentication() 
      .AddGoogle(o => 
      { 
       o.ClientId = Startup.Configuration["Authentication:Google:ClientId"]; 
       o.ClientSecret = Startup.Configuration["Authentication:Google:ClientSecret"]; 
      }); 
     services.AddAuthentication() 
      .AddTwitter(o => 
      { 
       o.ConsumerKey = Startup.Configuration["Authentication:Twitter:ConsumerKey"]; 
       o.ConsumerSecret = Startup.Configuration["Authentication:Twitter:ConsumerSecret"]; 
      }); 

     services.AddAuthentication() 
      .AddMicrosoftAccount(o => 
      { 
       o.ClientId= Startup.Configuration["Authentication:Microsoft:ClientId"]; 
       o.ClientSecret = Startup.Configuration["Authentication:Microsoft:ClientSecret"]; 
      }); 

     return services; 
    } 

    public static IServiceCollection AddCustomOpenIddict(this IServiceCollection services) 
    { 

     // Configure Identity to use the same JWT claims as OpenIddict instead 
     // of the legacy WS-Federation claims it uses by default (ClaimTypes), 
     // which saves you from doing the mapping in your authorization controller. 
     services.Configure<IdentityOptions>(options => 
     { 
      options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name; 
      options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject; 
      options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role; 

     }); 

     // Register the OpenIddict services. 
     services.AddOpenIddict() 
      // Register the Entity Framework stores. 
      .AddEntityFrameworkCoreStores<ApplicationDbContext>() 

      // Register the ASP.NET Core MVC binder used by OpenIddict. 
      // Note: if you don't call this method, you won't be able to 
      // bind OpenIdConnectRequest or OpenIdConnectResponse parameters. 
      .AddMvcBinders() 

      // Enable the token endpoint. 
      .EnableTokenEndpoint("/connect/token") 

      // Enable the password and the refresh token flows. 
      .AllowPasswordFlow() 
      .AllowRefreshTokenFlow() 

      // During development, you can disable the HTTPS requirement. 
      .DisableHttpsRequirement() 

      // Register a new ephemeral key, that is discarded when the application 
      // shuts down. Tokens signed using this key are automatically invalidated. 
      // This method should only be used during development. 
      .AddEphemeralSigningKey(); 

     // On production, using a X.509 certificate stored in the machine store is recommended. 
     // You can generate a self-signed certificate using Pluralsight's self-cert utility: 
     // https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip 
     // 
     // services.AddOpenIddict() 
     //  .AddSigningCertificate("7D2A741FE34CC2C7369237A5F2078988E17A6A75"); 
     // 
     // Alternatively, you can also store the certificate as an embedded .pfx resource 
     // directly in this assembly or in a file published alongside this project: 
     // 
     // services.AddOpenIddict() 
     //  .AddSigningCertificate(
     //   assembly: typeof(Startup).GetTypeInfo().Assembly, 
     //   resource: "AuthorizationServer.Certificate.pfx", 
     //   password: "OpenIddict"); 

     return services; 
    } 
    public static IServiceCollection AddCustomDbContext(this IServiceCollection services) 
    { 
     // Add framework services. 

     return services; 
    } 
    public static IServiceCollection RegisterCustomServices(this IServiceCollection services) 
    { 
     // New instance every time, only configuration class needs so its ok 
     services.Configure<SmsSettings>(options => Startup.Configuration.GetSection("SmsSettingsTwillio").Bind(options)); 
     services.AddTransient<UserResolverService>(); 
     services.AddTransient<IEmailSender, EmailSender>(); 
     services.AddTransient<ISmsSender, SmsSender>(); 
     services.AddScoped<ApiExceptionFilter>(); 
     return services; 
    } 

meine Pakete hier:

<ItemGroup> 
<PackageReference Include="AspNet.Security.OAuth.Introspection" Version="2.0.0-*" /> 
<PackageReference Include="AspNet.Security.OAuth.Validation" Version="2.0.0-*" /> 
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.AzureAppServicesIntegration" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" /> 
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.0.0" /> 
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" /> 
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" /> 
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.0.0" /> 
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" /> 
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="2.0.0" /> 
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" /> 
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" /> 
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" /> 
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" /> 
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.0.0" /> 
<PackageReference Include="Microsoft.AspNetCore.AngularServices" Version="1.1.0-beta-000002" /> 
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="1.0.0-beta3-final" /> 
<PackageReference Include="AspNet.Security.OAuth.LinkedIn" Version="1.0.0-beta3-final" /> 
<PackageReference Include="OpenIddict" Version="2.0.0-*" /> 
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="2.0.0-*" /> 
<PackageReference Include="OpenIddict.Mvc" Version="2.0.0-*" /> 
<PackageReference Include="SendGrid" Version="9.9.0" /> 
<PackageReference Include="MailKit" Version="1.18.0" /> 
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /> 
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="1.0.0" /> 
<PackageReference Include="Twilio" Version="5.6.3" /> 
<PackageReference Include="Stripe.net" Version="10.4.0" /> 
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> 
<PackageReference Include="Webpack" Version="4.0.0" /> 
<PackageReference Include="Serilog" Version="2.5.0" /> 
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" /> 
<PackageReference Include="Serilog.Sinks.Seq" Version="3.3.3" /> 
<PackageReference Include="Bogus" Version="17.0.1" /> 
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0"> 
    <PrivateAssets>All</PrivateAssets> 
</PackageReference> 
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.0"> 
    <PrivateAssets>All</PrivateAssets> 
</PackageReference> 

    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.0.0" PrivateAssets="All" /> 
    </ItemGroup> 

    <ItemGroup> 
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" /> 
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /> 
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" /> 
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" /> 
    </ItemGroup> 

Hier sind meine Protokolle:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 
    Request starting HTTP/1.1 GET http://localhost:44331/api/profile/test 
application/json; charset=UTF-8 
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 
    Authorization failed for user: (null). 
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 
    Authorization failed for user: (null). 
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] 
    Authorization failed for the request at filter 
'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. 
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] 
    Authorization failed for the request at filter 
'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. 
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1] 
    Executing ChallengeResult with authentication schemes(). 
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1] 
    Executing ChallengeResult with authentication schemes(). 
info: 
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[12] 
    AuthenticationScheme: Identity.Application was challenged. 
info: 
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[12] 
    AuthenticationScheme: Identity.Application was challenged. 
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] 
    Executed action 
AspNetCoreSpa.Server.Controllers.api.ProfileController.Test (AspNetCoreSpa) 
in 43.3105ms 
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] 
    Executed action 
AspNetCoreSpa.Server.Controllers.api.ProfileController.Test (AspNetCoreSpa) 
in 43.3105ms 
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 
    Request finished in 67.4133ms 302 
infoinfo: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 
    Request finished in 67.4133ms 302 
: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 
    Request starting HTTP/1.1 GET http://localhost:44331/Account/Login? 
ReturnUrl=%2Fapi%2Fprofile%2Ftest application/json; charset=UTF-8 
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 
    Request starting HTTP/1.1 GET http://localhost:44331/Account/Login? 
ReturnUrl=%2Fapi%2Fprofile%2Ftest application/json; charset=UTF-8 
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] 
    Executing action method 
AspNetCoreSpa.Server.Controllers.HomeController.Index (AspNetCoreSpa) with 
arguments ((null)) - ModelState is Valid 
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] 
    Executing action method 
AspNetCoreSpa.Server.Controllers.HomeController.Index (AspNetCoreSpa) with 
arguments ((null)) - ModelState is Valid 
info: Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor[1] 
    Executing ViewResult, running view at path /Views/Home/Index.cshtml. 
info: Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor[1] 
    Executing ViewResult, running view at path /Views/Home/Index.cshtml. 
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] 
    Executed action AspNetCoreSpa.Server.Controllers.HomeController.Index 
(AspNetCoreSpa) in 13.2746ms 
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] 
    Executed action AspNetCoreSpa.Server.Controllers.HomeController.Index 
(AspNetCoreSpa) in 13.2746ms 
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 
    Request finished in 79.2352ms 200 text/html; charset=utf-8 
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] 
    Request finished in 79.2352ms 200 text/html; charset=utf-8 

ich über die folgende Zeile fragen sich:

Berechtigung für Benutzer fehlgeschlagen: (null)

gefunden Bereits diese ASP.NET Core - Authorization failed for user: (null) aber es gibt noch keine Antwort und ich denke, es ist ein .net Kern 1 Problem.

Danke für Ihre Hilfe!

Mit freundlichen Grüßen Simon

+0

Ich habe das gleiche genaue Problem. Der 302 versucht mich zu ~/Konto/Login zu bringen. Dann bekomme ich einen 404, weil diese Route nicht existiert. – Bloodhound

+0

Ich habe auch das gleiche Problem nach dem Upgrade auf asp.net Core 2 – cuppy

+0

haben Sie dieses Problem lösen? – Hristo

Antwort

1

begegnete ich das gleiche Problem, und um das Problem zu lösen musste ich das Authentifizierungsschema in dem Autorisieren auf der Controller-Attribut enthalten.

In Ihrem Fall:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] 
[ServiceFilter(typeof(ApiExceptionFilter))] 
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)] 
public class BaseController : Controller 
{ 
    public BaseController() 
    { 
    } 
} 
0

Für mich wurde es zu Cross-Origin Resource Sharing (CORS) bezogen. Ich habe eine API in einem App-Service in Azure mit aktiviertem CORS. Ich habe die 302 verschwinden lassen, als ich die Anrufer der API der Liste der erlaubten Ursprünge hinzugefügt habe.

Ich musste dies tun, obwohl ich diese Ursprünge bereits in meinem aspnet Core-Startup-Code hinzugefügt hatte.

0

Wenn Sie AddIdentity aufrufen, wird die Cookie-Authentifizierung hinzugefügt, die die beabsichtigte JWT-Bearer-Authentifizierung außer Kraft setzt. Eine Möglichkeit, dies zu umgehen, besteht darin, den AddIdentity-Aufruf vor dem Einrichten der JWT-Authentifizierung zu verschieben. Im Folgenden ist der Code, der funktioniert für mich:

// setup identity 
services.AddIdentity<ApplicationUser, ApplicationRole>() 
    .AddEntityFrameworkStores<MyMoneyDbContext>() 
    .AddDefaultTokenProviders(); 

// setup Jwt authentication 
services.AddAuthentication(options => 
{ 
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 
}) 
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, jwtBearerOptions => 
{ 
    jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters 
    { 
     ValidateIssuerSigningKey = true, 
     ... 

Eine weitere Alternative ist AddIdentityCore zu verwenden, aber ich habe nie versucht, dass.

Verwandte Themen