Запретить перенаправление на / Аккаунт / Вход в asp.net core 2.2 - PullRequest
0 голосов
/ 26 декабря 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",
            });
        }

    }

Чтоне так с моей настройкой?Спасибо

1 Ответ

0 голосов
/ 26 декабря 2018

Привет и добро пожаловать в StackOverflow ?

Поведение, которое вы испытываете, связано с тем, что вы используете ASP.NET Identity.Когда вы вызываете services.AddIdentity, за кулисами регистрируется схема проверки подлинности на основе файлов cookie, которая устанавливается в качестве схемы вызова по умолчанию, как вы можете видеть в коде здесь, на GitHub .

Дажехотя вы зарегистрировали схему проверки подлинности cookie и задали ее в качестве схемы по умолчанию, конкретные схемы по умолчанию - например, AuthenticateScheme, ChallengeScheme, SignInScheme и т. д. - имеют преимущество.DefaultScheme используется системой аутентификации только в том случае, если конкретный не задан.

Чтобы ответить на ваш вопрос, вы можете применить параметры конфигурации к параметрам cookie удостоверений ASP.NET с помощью вспомогательного метода 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сама.

Дайте мне знать, как вы идете!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...