AuthorizeAttribute ничего не делает в ASP. NET Core 3 MVC - PullRequest
1 голос
/ 28 января 2020

У меня есть проект ASP. NET Core 3.1 MVC, с простой системой аутентификации на основе файлов cookie и несколькими ролями и политиками. DI обрабатывается с помощью Autofa c (не внутренней системы DI ASP. NET Core).

Я знаю, что мой пользователь правильно загружен соответствующими ролями и вызывает внутренние методы, такие как Context.User.IsInRole("Administrator")) (из представлений) работают должным образом.

Однако все мои AuthorizeAttribute не работают, в зависимости от содержимого моего автозагрузки, кажется ли, что они ничего не делают, или я всегда перенаправлен на страницу входа (даже если правильное требование выполнено).

Аннотация, подобная

[Authorize(Policy = "Administrator,Collaborator")]

или простому

[Authorize(Roles = "Administrator")]

, помещенному в метод действия, кажется, ничего не делает.

Я знаю, что порядок вызовов при запуске Configure и ConfigureServices имеют большое значение, но, несмотря на множество попыток и много чтения подобных вопросов на SO или где-то еще, я не смог заставить его работать, как ожидалось.

Ниже я поделился всем моим файлом Startup (извините за это), в надежде, что кто-нибудь сможет указать правильный порядок (или другой вид исправления, конечно), чтобы он работал для моего конкретного c случая.

Большое спасибо.

    public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }

        public void ConfigureServices(IServiceCollection services)
        {   
            services.AddControllersWithViews();
            services.AddRazorPages();
            services.AddOptions();
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
                {
                    options.Cookie.HttpOnly = true;
                    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
                    options.Cookie.SameSite = SameSiteMode.Strict;
                    options.LoginPath = "/Account/Login";
                    options.SlidingExpiration = true;
                    options.ExpireTimeSpan = new TimeSpan(0, 24, 0, 0);
                    options.AccessDeniedPath = "/Error/RightError";
                });

            services.AddAuthorization(options =>
            {
                options.AddPolicy(SecurityPolicies.AdministratorOnly, policy => 
                    policy.RequireClaim(ClaimTypes.Role, UserRoles.Administrator));
                options.AddPolicy(SecurityPolicies.AdministratorOrCollaborator, policy => 
                    policy.RequireClaim(ClaimTypes.Role, UserRoles.Administrator, UserRoles.Collaborator));
            });

            services.AddSession(options => options.IdleTimeout = TimeSpan.FromHours(4));
            services.AddMvc(options => options.Filters.Add(new AuthorizeFilter()))
            .AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());

            services.AddKendo();
        }

        // ConfigureContainer is where you can register things directly
        // with Autofac. This runs after ConfigureServices so the things
        // here will override registrations made in ConfigureServices.
        // Don't build the container; that gets done for you by the factory.
        public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterModule(new MyFrontModule());
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseExceptionHandler(ProcessError);
            }
            else
            {
                app.UseExceptionHandler("/Error/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseSession();
            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseCookiePolicy();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");

                    endpoints.MapControllers();
                endpoints.MapRazorPages();
            });

            var ci = new CultureInfo("fr-FR")
            {
                NumberFormat = { NumberDecimalSeparator = ".", CurrencyDecimalSeparator = "." }
            };

            app.UseRequestLocalization(new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture(ci),
                SupportedCultures = new List<CultureInfo> { ci },
                SupportedUICultures = new List<CultureInfo> { ci }
            });
        }

        private void ProcessError(IApplicationBuilder appError)
        {
            appError.Run(async context =>
            {
                // Not relevant for my question
            });
        }
    }

Я также читал, что Json Сериализатор может что-то изменить, я использую Newtonsoft с DefaultContractResolver (как указано выше), и я использую компоненты интерфейса Telerik.

Большое спасибо за любые полезные советы!

1 Ответ

0 голосов
/ 18 февраля 2020

Как объяснено в вопросе, у меня никогда не было возможности, чтобы атрибут Authorize работал должным образом, так как мои потребности в правильном управлении были довольно просты, в качестве обходного пути я только что реализовал очень простой FilterAttribute для проверки прав на основе на собственных ролях.

public class RoleRequirementAttribute : TypeFilterAttribute
{
    public RoleRequirementAttribute(params string[] claimValues) 
        : base(typeof(ClaimRequirementFilter))
    {
        Arguments = new []{ claimValues.Select(cv => new Claim(ClaimTypes.Role, cv)) };
    }
}

public class ClaimRequirementFilter : IAuthorizationFilter
{
    readonly IEnumerable<Claim> _claims;

    public ClaimRequirementFilter(IEnumerable<Claim> claims)
    {
        _claims = claims;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var hasClaim =  context.HttpContext.User.Claims.Any(owned => _claims.Any(required => owned.Type == required.Type && owned.Value == required.Value));

        if (!hasClaim)
        {
            context.Result = new ForbidResult();
        }
    }
}
...