我有一个MVC应用程序,它使用Forms身份验证对Active Directory进行身份验证。由于我的MVC应用程序的大小已经很大,很明显我正在进行的角色检查正在变得越来越分散。我想替换像:
这样的东西 [Authorize(Roles = "Staff")]
和Thread.CurrentPrincipal.IsInRole("Staff")
带有以下内容:
[AuthorizePermission(Permission.CanDoSomething)]
和Thead.CurrentPrincipal.HasPermission(Permission.CanDoSomething)
其中Permission是枚举。现在我想我可以定义每个AD角色在web.config中具有哪些权限,如下所示:
<role name="Staff">
<permissions>
<add name="CreateEditDeleteSomething" />
<add name="PublishSomething" />
<add name="QueryUsers" />
</permissions>
</role>
然后我可以实现一个IPrincipal扩展方法 - HasPermission(Permission permission)
。这将查看用户是否属于任何具有web.config中定义的传入权限的AD组。这将允许我更改特定AD goup的权限,而无需更改代码或更新现有测试。然后,自定义授权属性可以调用HasPermission方法。
这种方法是否正确或是否有更好的方法来简化我在应用程序中的角色?我在这里和网络上看到了很多例子,但它们似乎过于复杂。我可以通过检查HasPermission中我的web.config角色设置的传入权限来实现这一点吗? IPrincipal将具有其AD角色,因此可以直接确定允许的权限吗?
任何帮助表示赞赏!
答案 0 :(得分:1)
权限比角色复杂得多。
通常可以有权限组,例如CreateEditDelete ......但它们也可以是粒度子集,例如“创建”,“编辑”,“删除”
我解决此问题的方法是创建一个PermissionsManger类,该类可以确定用户应该赋予业务规则上下文及其AD角色的权限。
我使用按位标记来帮助简化细化权限的复杂性。
如何将角色映射到权限完全取决于您。
using System;
using System.Linq;
using System.Security.Principal;
// Install-Package FluentAssertions -Pre
using FluentAssertions;
public static class ExtensionsForIPrincipal
{
public static bool HasPermission(this IPrincipal principal, Permissions permission)
{
return PermissionsManager.GetUserPermissions(principal).HasFlag(permission);
}
public static bool IsInRole(this IPrincipal principal, params string[] roleNames)
{
return roleNames.Any(principal.IsInRole);
}
}
public static class PermissionsManager
{
public static Permissions GetUserPermissions(IPrincipal user)
{
if ( user.IsInRole("admin") )
{
return Permissions.All;
}
var userPermissions = Permissions.None;
if ( user.IsInRole("staff", "user") )
{
userPermissions |= Permissions.QueryUsers;
}
if ( user.IsInRole("staff") )
{
userPermissions |= Permissions.PermissionsCreateEditDeleteSomething | Permissions.QueryUsers;
}
if ( user.IsInRole("editor") )
{
userPermissions |= Permissions.PublishSomething;
}
return userPermissions;
}
}
[Flags]
public enum Permissions
{
None = 0,
CreateSomething = 1,
EditSomething = 2,
DeleteSomething = 4,
PublishSomething = 8,
QueryUsers = 16,
PermissionsCreateEditDeleteSomething = CreateSomething | EditSomething | DeleteSomething,
All = PermissionsCreateEditDeleteSomething | PublishSomething | QueryUsers
}
internal class Program
{
private static void Main(string[] args)
{
IPrincipal admin = Create("james", "admin");
PermissionsManager.GetUserPermissions(admin).ShouldBeEquivalentTo(Permissions.All);
admin.HasPermission(Permissions.None).Should().BeTrue();
admin.HasPermission(Permissions.EditSomething).Should().BeTrue();
admin.HasPermission(Permissions.PermissionsCreateEditDeleteSomething).Should().BeTrue();
admin.HasPermission(Permissions.PublishSomething).Should().BeTrue();
admin.HasPermission(Permissions.QueryUsers).Should().BeTrue();
admin.HasPermission(Permissions.All).Should().BeTrue();
IPrincipal editor = Create("susan", "editor", "staff");
editor.HasPermission(Permissions.None).Should().BeTrue();
editor.HasPermission(Permissions.EditSomething).Should().BeTrue();
editor.HasPermission(Permissions.PermissionsCreateEditDeleteSomething).Should().BeTrue();
editor.HasPermission(Permissions.QueryUsers).Should().BeTrue();
editor.HasPermission(Permissions.PublishSomething).Should().BeTrue();
editor.HasPermission(Permissions.All).Should().BeTrue();
IPrincipal staff = Create("michael", "staff");
staff.HasPermission(Permissions.None).Should().BeTrue();
staff.HasPermission(Permissions.EditSomething | Permissions.DeleteSomething).Should().BeTrue();
staff.HasPermission(Permissions.PermissionsCreateEditDeleteSomething).Should().BeTrue();
staff.HasPermission(Permissions.QueryUsers).Should().BeTrue();
staff.HasPermission(Permissions.PublishSomething).Should().BeFalse();
staff.HasPermission(Permissions.All).Should().BeFalse();
IPrincipal user = Create("bob", "user");
user.HasPermission(Permissions.None).Should().BeTrue();
user.HasPermission(Permissions.EditSomething).Should().BeFalse();
user.HasPermission(Permissions.PermissionsCreateEditDeleteSomething).Should().BeFalse();
user.HasPermission(Permissions.QueryUsers).Should().BeTrue();
user.HasPermission(Permissions.PublishSomething).Should().BeFalse();
user.HasPermission(Permissions.All).Should().BeFalse();
IPrincipal anon = Create("anonymous");
anon.HasPermission(Permissions.None).Should().BeTrue();
anon.HasPermission(Permissions.EditSomething).Should().BeFalse();
anon.HasPermission(Permissions.PermissionsCreateEditDeleteSomething).Should().BeFalse();
anon.HasPermission(Permissions.QueryUsers).Should().BeFalse();
anon.HasPermission(Permissions.PublishSomething).Should().BeFalse();
anon.HasPermission(Permissions.All).Should().BeFalse();
Console.WriteLine("All tests passed");
Console.ReadLine();
}
private static IPrincipal Create(string name, params string[] roles)
{
return new GenericPrincipal(new GenericIdentity(name), roles);
}
}