Asp.net-Core-2.2

防止在 asp.net core 2.2 中重定向到 /Account/Login

  • December 25, 2018

/Account/Login當使用者未登錄時,我試圖阻止應用程序重定向到asp.net core 2.2。

即使我寫LoginPath = new PathString("/api/contests");了任何未經授權的請求仍然被重定向到/Account/Login

這是我的 Startup.cs:

using System;
using System.Reflection;
using AutoMapper;
using Contest.Models;
using Contest.Tokens;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Swashbuckle.AspNetCore.Swagger;

namespace Contest
{
   public class Startup
   {
       public IConfiguration Configuration { get; }

       public Startup(IConfiguration configuration)
       {
           Configuration = configuration;
       }

       // This method gets called by the runtime. Use this method to add services to the container.
       public void ConfigureServices(IServiceCollection services)
       {

           services.AddAutoMapper();

           // In production, the React files will be served from this directory
           services.AddSpaStaticFiles(configuration =>
           {
               configuration.RootPath = "clientapp/build";
           });

           // ===== Add our DbContext ========
           string connection = Configuration.GetConnectionString("DBLocalConnection");
           string migrationAssemblyName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
           services.AddDbContext<ContestContext>(options =>
                   options.UseSqlServer(connection,
                   sql => sql.MigrationsAssembly(migrationAssemblyName)));

           // ===== Add Identity ========
           services.AddIdentity<User, IdentityRole>(o =>
           {
               o.User.RequireUniqueEmail = true;
               o.Tokens.EmailConfirmationTokenProvider = "EMAILCONF";
               // I want to be able to resend an `Email` confirmation email
               // o.SignIn.RequireConfirmedEmail = true; 
           }).AddRoles<IdentityRole>()
               .AddEntityFrameworkStores<ContestContext>()
               .AddTokenProvider<EmailConfirmationTokenProvider<User>("EMAILCONF")
               .AddDefaultTokenProviders();

           services.Configure<DataProtectionTokenProviderOptions>(o =>
               o.TokenLifespan = TimeSpan.FromHours(3)
           );

           services.Configure<EmailConfirmationTokenProviderOptions>(o =>
               o.TokenLifespan = TimeSpan.FromDays(2)
           );

           // ===== Add Authentication ========

           services.AddAuthentication(o => o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme)
               .AddCookie(options =>
               {
                   options.Cookie.Name = "auth_cookie";
                   options.Cookie.SameSite = SameSiteMode.None;
                   options.LoginPath = new PathString("/api/contests");
                   options.AccessDeniedPath = new PathString("/api/contests");
                   options.Events = new CookieAuthenticationEvents
                   {
                       OnRedirectToLogin = context =>
                       {
                           context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                           return Task.CompletedTask;
                       },
                   };
               });

           // ===== Add Authorization ========

           services.AddAuthorization(o =>
           {

           });

           services.AddCors();

           // ===== Add MVC ========
           services.AddMvc(config =>
           {
               var policy = new AuthorizationPolicyBuilder()
                                   .RequireAuthenticatedUser()
                                   .Build();
               config.Filters.Add(new AuthorizeFilter(policy));
           })
               .AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore)
               .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

           // ===== Add Swagger ========
           services.AddSwaggerGen(c =>
           {
               c.SwaggerDoc("v1", new Info
               {
                   Title = "Core API",
                   Description = "Documentation",
               });

               var xmlPath = $"{System.AppDomain.CurrentDomain.BaseDirectory}Contest.xml";
               c.IncludeXmlComments(xmlPath);
           });

       }

       // 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();
           }
           else
           {
               app.UseExceptionHandler("/Error");
               app.UseHsts();
           }

           app.UseHttpsRedirection();
           app.UseSpaStaticFiles(new StaticFileOptions()
           {

           });

           app.UseCors(policy =>
           {
               policy.AllowAnyHeader();
               policy.AllowAnyMethod();
               policy.AllowAnyOrigin();
               policy.AllowCredentials();
           });

           app.UseAuthentication();

           app.UseMvc();

           if (env.IsDevelopment())
           {
               app.UseSwagger();
               app.UseSwaggerUI(c =>
               {
                   c.SwaggerEndpoint("/swagger/v1/swagger.json", "Core API");
               });
           }

           app.UseSpa(spa =>
           {
               spa.Options.SourcePath = "clientapp";

               if (env.IsDevelopment())
               {
                   // spa.UseReactDevelopmentServer(npmScript: "start");
                   spa.UseProxyToSpaDevelopmentServer("http://localhost:3000");
               }
           });

       }

   }
}

我設法通過創建一個控制器來處理這條路線來繞過這個:

[Route("/")]
[ApiController]
public class UnauthorizedController : ControllerBase
{
   public UnauthorizedController()
   {

   }

   [HttpGet("/Account/Login")]
   [AllowAnonymous]
   public IActionResult Login()
   {
       HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
       return new ObjectResult(new
       {
           StatusCode = StatusCodes.Status401Unauthorized,
           Message = "Unauthorized",
       });
   }

}

我的設置有什麼問題?謝謝

你好,歡迎來到 StackOverflow 👋

您遇到的行為與您使用 ASP.NET Identity 的事實有關。當您呼叫 時services.AddIdentity,會在後台註冊一個基於 cookie 的身份驗證方案並將其設置為預設質詢方案,如您在 GitHub 上的程式碼中所見。

即使您自己註冊了一個 cookie 身份驗證方案並將其設置為預設方案,但特定的預設方案(如AuthenticateSchemeChallengeSchemeSignInScheme等)優先。DefaultScheme僅當未設置特定時才由身份驗證系統使用。

要回答您的問題,您可以使用輔助方法將配置設置應用於 ASP.NET 身份 cookie 選項services.ConfigureApplicationCookie,如下所示:

// ===== Add Identity ========
services.AddIdentity<User, IdentityRole>(o =>
{
   o.User.RequireUniqueEmail = true;
   o.Tokens.EmailConfirmationTokenProvider = "EMAILCONF";
   // I want to be able to resend an `Email` confirmation email
   // o.SignIn.RequireConfirmedEmail = true; 
}).AddRoles<IdentityRole>()
   .AddEntityFrameworkStores<ContestContext>()
   .AddTokenProvider<EmailConfirmationTokenProvider<User>("EMAILCONF")
   .AddDefaultTokenProviders();

services.Configure<DataProtectionTokenProviderOptions>(o =>
   o.TokenLifespan = TimeSpan.FromHours(3)
);

services.Configure<EmailConfirmationTokenProviderOptions>(o =>
   o.TokenLifespan = TimeSpan.FromDays(2)
);

// ===== Configure Identity =======
service.ConfigureApplicationCookie(options =>
{
   options.Cookie.Name = "auth_cookie";
   options.Cookie.SameSite = SameSiteMode.None;
   options.LoginPath = new PathString("/api/contests");
   options.AccessDeniedPath = new PathString("/api/contests");

   // Not creating a new object since ASP.NET Identity has created
   // one already and hooked to the OnValidatePrincipal event.
   // See https://github.com/aspnet/AspNetCore/blob/5a64688d8e192cacffda9440e8725c1ed41a30cf/src/Identity/src/Identity/IdentityServiceCollectionExtensions.cs#L56
   options.Events.OnRedirectToLogin = context =>
   {
       context.Response.StatusCode = StatusCodes.Status401Unauthorized;
       return Task.CompletedTask;
   };
});

這也意味著您可以安全地刪除添加基於 cookie 的身份驗證方案的部分,因為這由 ASP.NET Identity 本身負責。

讓我知道你怎樣去!

引用自:https://stackoverflow.com/questions/53925609