简体   繁体   English

AuthorizeAttribute 在 ASP.NET Core 3 MVC 中什么都不做

[英]AuthorizeAttribute does nothing in ASP.NET Core 3 MVC

I have an ASP.NET Core 3.1 MVC project, with a simple authentication system based on cookies, and a few roles and policies.我有一个 ASP.NET Core 3.1 MVC 项目,有一个基于 cookie 的简单身份验证系统,以及一些角色和策略。 DI is handled with Autofac (not internal DI system of ASP.NET Core). DI 由 Autofac(不是 ASP.NET Core 的内部 DI 系统)处理。

I know my user is correctly loaded with proper roles, and calls to internal methods like Context.User.IsInRole("Administrator")) (from views) are working as expected.我知道我的用户正确加载了适当的角色,并且对Context.User.IsInRole("Administrator"))等内部方法的调用(从视图中)按预期工作。

However, all my AuthorizeAttribute are not working, depending of the content of my Startup whether they seem to do nothing, or I am always redirected to login page (even if the right requirement is fulfilled).但是,我所有的AuthorizeAttribute都不起作用,这取决于我的 Startup 的内容是它们似乎什么都不做,还是我总是被重定向到登录页面(即使满足了正确的要求)。

An annotation like像这样的注释

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

or a simple或者一个简单的

[Authorize(Roles = "Administrator")]

placed on an action method seems to do nothing.放在一个动作方法上似乎什么都不做。

I know that order of calls in startup Configure and ConfigureServices matter a lot, but despite many attempts and a lot of reading of similar questions on SO or somewhere else, I was not able to make it work as expected.我知道启动ConfigureConfigureServices的调用顺序很重要,但是尽管进行了多次尝试并阅读了很多关于 SO 或其他地方的类似问题,我还是无法使其按预期工作。

I share below my whole Startup file (sorry for that), in hope somebody will be able to point the correct order (or another kind of fix of course), to make it work for my specific case.我在下面分享我的整个Startup文件(对此很抱歉),希望有人能够指出正确的顺序(当然或其他类型的修复),以使其适用于我的特定情况。

Thanks a lot.非常感谢。

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

I also read that Json Serializer may change something, I am using Newtonsoft with DefaultContractResolver (as above), and I am using Telerik UI components.我还读到 Json Serializer 可能会改变一些东西,我正在使用 Newtonsoft 和 DefaultContractResolver(如上所述),并且我正在使用 Telerik UI 组件。

Thanks a lot for any useful advice !非常感谢任何有用的建议!

As explained in question, I have never been able to have Authorize attribute working as expected, so as my needs in right management were pretty simple, as a workaround I've just implemented a very straightforward FilterAttribute to verify rights based on owned roles.正如问题所解释的,我从来没有让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();
        }
    }
}

I resolved this issue by adding .AddRoles<IdentityRole to the identity setting in the startup file.我通过将 .AddRoles<IdentityRole 添加到启动文件中的身份设置解决了这个问题。

        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddRoles<IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM