为啥 [Authorize(Roles = "Admin")] 不能在具有 ASP.NET 标识的 MVC 5 RTM 中工作?

Posted

技术标签:

【中文标题】为啥 [Authorize(Roles = "Admin")] 不能在具有 ASP.NET 标识的 MVC 5 RTM 中工作?【英文标题】:Why isn't [Authorize(Roles = "Admin")] working in MVC 5 RTM with ASP.NET Identity?为什么 [Authorize(Roles = "Admin")] 不能在具有 ASP.NET 标识的 MVC 5 RTM 中工作? 【发布时间】:2013-12-24 01:41:13 【问题描述】:

[Authorize(Roles = "Admin")] 在 MVC 5 RTM 中与 ASP.NET Identity 是否可以开箱即用?

我没有运气。请注意,[Authorize][Authorize(Users = "AdminUser")] 工作得很好,并且 AspNetUserRoles 和 AspNetRoles 表按照我的预期填充,建立了 AdminUser 用户和 Admin 角色之间的关系。这个问题似乎是特定于角色的。

【问题讨论】:

Authorize 属性在 MVC 5 和 ASP.NET Identity 中开箱即用。您遇到的问题的描述不是很清楚。您是说仅当您使用 Admin 角色而不是 AdminUser 角色时才会失败。显示一些关于您如何播种角色并将用户映射到角色的代码。 Authorize 确实可以开箱即用,但设置 Roles 不能按预期工作。当我的用户 AdminUser 被分配给角色 Admin 并且我应用 [Authorize(**Roles** = "Admin")] 属性时,我收到访问被拒绝,这不是预期的。当我应用 [Authorize(**Users**= "AdminUser")] 属性时,我可以按预期进行访问。就我的种子代码而言,我的表看起来与 AspNetUserRoles 表中的 AdminUser 用户和 Admin 角色之间的关系完全一样。使用 Roles = "..." 对新的 MVC 5 站点有用吗? @KevinJunghans 我不知道这是否重要,但唯一未填充的表是 AspNetUserClaims 表。 声明是可选的,用于自定义授权过程。如果您想查看一个工作示例,请访问 SimpleSecurity Project simplesecurity.codeplex.com/SourceControl/latest#AspNetIdentity/…。您将看到在 Home 控制器中的 About 操作上使用了 AuthorizeAttribute。使用“用户”和“密码”登录,即可访问此视图。 谢谢@KevinJunghans。您的反馈鼓励我继续努力。 【参考方案1】:

用户可能需要重新进行身份验证才能接收包含管理员角色成员身份的新声明。由于 MVC 5 使用 ASP.NET Identity 开箱即用,并且默认情况下在 MVC 5 中,ASP.NET Identity 在用户的 cookie 中存储类似角色的声明,该信息可能会变得陈旧(因此数据库说一件事,但用户的 cookie 说别的东西)。重新验证用户身份将刷新他们的声明,包括用户角色声明,以匹配数据库的当前状态。

例如:

如果用户在被分配到数据库中的管理员角色之前登录,则该用户将被授予声明,但他们不会将其分配给管理员角色。如果稍后将它们添加到管理员角色,则存储在其 cookie 中的声明不会自动更新。相反,只有数据库已更新,应用程序必须重新验证它们,然后才能将旧声明替换为包含管理员角色成员身份的新声明。让用户手动退出并重新登录是重新验证该用户的最明显方式。

这是一篇关于Using Claims in ASP.NET Identity的文章

【讨论】:

这让我发疯了。没有考虑注销并重新登录,因为当角色拒绝访问时,它正在显示登录页面。我在没有先注销的情况下登录该页面。啊!【参考方案2】:

答案是 UserManager 的 DbContext 必须启用延迟加载,以便用户角色以通常的、预期的方式在应用程序中显示。事实证明,并非我的所有代码都是“开箱即用”的。我已经稍微定制了我的 DbContext。希望将来 Microsoft 将通过确保集合加载类似 userDbContext.Users.Include(o => o.Roles).SingleOrDefault(...) 的内容来回避此集成错误。

做:ApplicationDbContext.Configuration.LazyLoadingEnabled = true; 请勿:ApplicationDbContext.Configuration.LazyLoadingEnabled = false;

请注意,如果您的代码中未设置ApplicationDbContext.Configuration.LazyLoadingEnabled,则默认为true。所以离开这条线就像将它设置为true一样好。

这是我对禁用延迟加载时发生的情况的猜测,当 UserManager 或 UserStore 访问它时,IdentityUser / ApplicationUser 对象的 Roles 属性为 null 或为空,因为未手动加载该集合.然后代码继续执行,就像没有为用户分配任何角色,而事实上该集合根本没有加载。

啊,无声失败的香气。是不是代码只有在事情看起来不正确时才会发出一些噪音。

【讨论】:

那我猜你的问题和我的不一样。您可能想按照我的路径来找出解决方案。我创建了一个新的 Web 应用程序,并将其中的所有内容与我已经工作了几天的那个进行了绝对的比较。一种方法是,假设您已经在使用源代码管理,将项目中的所有相关文件替换为新项目中的文件,并使用您最喜欢的源代码管理工具查看更改的内容。 完美我刚刚在 MyAppDbContext 中添加了您的代码,它继承了 IdentityDbContext 并且它运行良好:)。 public class MyDbContext: IdentityDbContext<ApplicationUser> new public DbSet<ApplicationRole> Roles get; set; public MyDbContext() : base("DefaultConnection") this.Configuration.LazyLoadingEnabled = true; 【参考方案3】:
<system.webServer>
<modules>
    <remove name="RoleManager" />
</modules>
</system.webServer>

【讨论】:

想解释一下为什么这对您有帮助?

以上是关于为啥 [Authorize(Roles = "Admin")] 不能在具有 ASP.NET 标识的 MVC 5 RTM 中工作?的主要内容,如果未能解决你的问题,请参考以下文章

Authorize(Roles = "Admin") 总是返回 ACCESS DENIED

.NET Core 本地开发时绕过或关闭[Authorize(Roles="")]

如何解决始终返回使用 [Authorize(Roles = "Manager")] 的未经授权状态?

ASP.NET Core 身份 [Authorize(Roles ="ADMIN")] 不起作用

`[Authorize (Roles="Role")]` 不起作用,User.IsInRole("Role") 始终为 false

如何使用 <sec:authorize access="hasRole('ROLES)"> 来检查多个角色?