2017-09-04 84 views
5

我正尝试将此项目从.net core 1.1迁移到2.0,但在登录成功后出现问题 https://github.com/asadsahi/AspNetCoreSpa。登录后,我的GET api调用e。 G。到https://localhost:44331/api/profile/test结束了一个重定向(302),我不知道为什么。我收到一个不记名令牌,看起来很好。ASP.NET Core 2 API调用被重定向(302)

请求头格式: 授权:承载[令牌]

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

我IServiceCollection的扩展:

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

这里我的包:

<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> 

这里是我的日志:

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 

我想知道下面一行:

授权失败,用户(空)

已经发现这个ASP.NET Core - Authorization failed for user: (null) 但还没有答案,我认为它是一个.net核心1问题。

感谢您的帮助!

问候 西蒙

+0

我有同样的确切问题。 302正试图带我去〜/帐户/登录。然后我得到一个404,因为这条路线不存在。 – Bloodhound

+0

升级到asp.net core 2后,我也面临同样的问题 – cuppy

+0

你解决了这个问题吗? – Hristo

回答

1

我遇到了同样的问题,为了解决这个问题,我不得不包括在授权认证方案控制器上的属性。

你的情况:

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

对于我来说,这是涉及到跨来源资源共享(CORS)。我在启用CORS的Azure App Service中有一个API。当我将API的调用者添加到允许的来源列表中时,我得到了302消失。

即使我已经在我的aspnet核心启动代码中添加了这些起源,我也必须这样做。

0

当您调用AddIdentity时,它会添加Cookie身份验证,该身份验证将覆盖您预期的JWT承载身份验证。解决此问题的一种方法是在设置JWT身份验证之前移动AddIdentity调用。以下是对我的作品的代码:

// 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, 
     ... 

另一种方法是使用AddIdentityCore但我从来没有尝试过。