3

フォーム認証を使用してActiveDirectoryに対して認証するMVCアプリケーションがあります。私のMVCアプリケーションのサイズが大きくなるにつれて、私が行っている役割チェックがますます断片化されていることが明らかになりました。次のようなものを置き換えたい:

[Authorize(Roles = "Staff")]Thread.CurrentPrincipal.IsInRole("Staff")

次のようなものがあります。

[AuthorizePermission(Permission.CanDoSomething)]Thead.CurrentPrincipal.HasPermission(Permission.CanDoSomething)

ここで、Permissionは列挙型です。今、私は次のようにweb.configで各ADロールが持つ権限を定義できると考えていました。

  <role name="Staff">
    <permissions>
      <add name="CreateEditDeleteSomething" />
      <add name="PublishSomething" />
      <add name="QueryUsers" />
    </permissions>
  </role>

次に、IPrincipal拡張メソッドを実装できます- HasPermission(Permission permission)。これにより、web.configで定義されているように渡された権限を持つADグループのいずれかにユーザーがログインするかどうかが確認されます。これにより、コードを変更したり、既存のテストを更新したりすることなく、特定のADグループが持つ権限を変更できます。次に、カスタムのAuthorize属性でHasPermissionメソッドを呼び出すことができます。

このアプローチは正しいですか、それともアプリケーション内での役割を単純化するためのより良い方法がありますか?私はここやウェブの周りで多くの例を見てきましたが、それらは非常に複雑なようです。HasPermissionのweb.configロール設定に対して渡されたPermissionをチェックするだけで、これを達成できますか?IPrincipalにはADの役割があるので、許可されているアクセス許可を決定するのは簡単ですか?

助けていただければ幸いです。

4

1 に答える 1

1

権限は役割よりもはるかに複雑です。

多くの場合、CreateEditDelete ...などの権限グループが存在する可能性がありますが、「作成」、「編集」、「削除」などの詳細なサブセットにすることもできます。

この問題を解決する方法は、ユーザーがビジネスルールコンテキストとそのADロールに与える必要のあるアクセス許可を決定できるPermissionsMangerクラスを作成することです。

きめ細かい権限の複雑さを単純化するために、ビット単位のフラグを使用しました。

ロールを権限にマップする方法は完全にあなた次第です。

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 に答える