【问题标题】:AuthorizeAttribute does nothing in ASP.NET Core 3 MVCAuthorizeAttribute 在 ASP.NET Core 3 MVC 中什么都不做
【发布时间】:2020-05-13 18:13:33
【问题描述】:

我有一个 ASP.NET Core 3.1 MVC 项目,有一个基于 cookie 的简单身份验证系统,以及一些角色和策略。 DI 由 Autofac 处理(不是 ASP.NET Core 的内部 DI 系统)。

我知道我的用户已正确加载了适当的角色,并且对 Context.User.IsInRole("Administrator")) 等内部方法的调用(来自视图)按预期工作。

但是,我所有的AuthorizeAttribute 都无法正常工作,这取决于我的 Startup 内容是否它们似乎什么都不做,或者我总是被重定向到登录页面(即使满足了正确的要求)。

类似注释

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

还是简单的

[Authorize(Roles = "Administrator")]

放在一个动作方法上似乎什么都不做。

我知道启动 ConfigureConfigureServices 中的调用顺序很重要,但是尽管在 SO 或其他地方进行了多次尝试和大量阅读类似问题,但我无法使其按预期工作.

我在我的整个Startup 文件下面分享(对此感到抱歉),希望有人能够指出正确的顺序(或者当然是另一种修复方法),以使其适用于我的具体情况。

非常感谢。

    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 Serializer 可能会改变一些东西,我正在使用 Newtonsoft 和 DefaultContractResolver(如上所述),并且我正在使用 Telerik UI 组件。

非常感谢任何有用的建议!

【问题讨论】:

  • [Authorize] 不指定角色/策略是否有效?
  • 我重现您的问题并将代码更改为options.Cookie.SecurePolicy = CookieSecurePolicy.None; 虽然我不知道为什么但它可以工作...
  • @XingZou 我没有指定,但问题发生在开发环境中的 IIS Express 中,尚未在生产中测试。我已经尝试过您的解决方案,但不幸的是它并没有改变任何东西。我还测试了 SameAsRequest 以防万一(因为它会比 None 更好)
  • @AlexanderGoldabin 能够在不被记录的情况下打开控制器或操作,我应该在其上方放置 AllowAnonymous。如果我不指定任何内容,则需要进行身份验证。所以我不知道我是否应该在不指定任何内容或指定不带参数的授权之间观察不同的行为。
  • 我有点迷路了。你说属性不起作用是什么意思?您已通过身份验证,但无法调用方法?反之亦然 - 匿名呼叫绕过 [Authorize] 属性?

标签: c# .net asp.net-mvc asp.net-core asp.net-core-mvc


【解决方案1】:

正如问题所解释的,我从来没有能够让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();
        }
    }
}

【讨论】:

    【解决方案2】:

    我通过将 .AddRoles

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

    【讨论】:

      猜你喜欢
      • 2015-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多