3

我有一个 MVC 应用程序,它使用表单身份验证对 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 组的权限,而无需更改代码或更新现有测试。然后自定义授权属性可以调用 HasPermission 方法。

这种方法是正确的还是有更好的方法来简化我在应用程序中的角色?我在这里和网络上看到了很多例子,但它们似乎过于复杂。我可以通过在 HasPermission 中针对我的 web.config 角色设置检查传入的权限来实现这一点吗?IPrincipal 将具有其 AD 角色,因此确定允许的权限是否很简单?

任何帮助表示赞赏!

4

1 回答 1

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);
    }
}
于 2012-09-07T00:44:30.067 回答