web-dev-qa-db-ja.com

MVCロール承認

現在ログインしているユーザーのロールをチェックするロール承認メカニズムを実装しようとしています。ユーザーが適切なロールを持っている場合は許可され、そうでない場合はエラービューを表示します。

問題は、ユーザーがコントローラーの以下のメソッドにアクセスしようとすると、RoleAuthorizationAttributeクラスにアクセスして検証されるが、コントローラーのメソッドが実行されないことです。

注:ユーザーにはクライアントの役割があります

コントローラー方式

[RoleAuthorization(Roles = "Client, Adminsitrator")]
    public ActionResult addToCart(int ProductID, string Quantity)
    {
        tempShoppingCart t = new tempShoppingCart();
        t.ProductID = ProductID;
        t.Username = User.Identity.Name;
        t.Quantity = Convert.ToInt16(Quantity);

        new OrdersService.OrdersClient().addToCart(t);
        ViewData["numberOfItemsInShoppingCart"] = new OrdersService.OrdersClient().getNoOfItemsInShoppingCart(User.Identity.Name);
        ViewData["totalPriceInSC"] = new OrdersService.OrdersClient().getTotalPriceOfItemsInSC(User.Identity.Name);
        return PartialView("quickShoppingCart", "Orders");
    }

ロール認証クラス

[System.AttributeUsage(System.AttributeTargets.All,AllowMultiple = false, Inherited = true)]
public sealed class RoleAuthorizationAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {


        List<String> requiredRoles = Roles.Split(Convert.ToChar(",")).ToList();

        List<Role> allRoles = new UsersService.UsersClient().GetUserRoles(filterContext.HttpContext.User.Identity.Name).ToList();


        bool Match = false;

        foreach (String s in requiredRoles)
        {
            foreach (Role r in allRoles)
            {
                string rName = r.RoleName.Trim().ToString();
                string sName = s.Trim();
                if (rName == sName)
                {
                    Match = true;
                }
            }
        }

        if (!Match)
        {
            filterContext.Result = new ViewResult { ViewName = "AccessDenied" };
        }

        base.OnAuthorization(filterContext);

    }
}

私が間違っていることを教えてください

13
drinu16

データベースにユーザーのロールがあるため、データベースに対してチェックする必要があったため、このメソッドをglobal.asaxに含めました。

protected void Application_AuthenticateRequest(object sender, EventArgs args)
    {
        if (Context.User != null)
        {
            IEnumerable<Role> roles = new UsersService.UsersClient().GetUserRoles(
                                                    Context.User.Identity.Name);


            string[] rolesArray = new string[roles.Count()];
            for (int i = 0; i < roles.Count(); i++)
            {
                rolesArray[i] = roles.ElementAt(i).RoleName;
            }

            GenericPrincipal gp = new GenericPrincipal(Context.User.Identity, rolesArray);
            Context.User = gp;
        }
    }

その後、私は通常を使用することができます

[Authorize(Roles = "Client, Administrator")]

コントローラーのactionResultメソッドの上

これはうまくいきました。

16
drinu16

元のコードは近くにありましたが、問題は次のとおりです。

base.OnAuthorization(filterContext);

基本クラスを無条件に呼び出すと、装飾されたロールがUsersServiceと組み込みのロールプロバイダーの両方に存在する必要があります。ロールプロバイダーが同じロールセットを返すように構成されていない場合(既定のAuthorizeAttributeで十分でない場合はそうではありません)、明らかに、承認テストは常にfalseを返します。

代わりに、次のような個別のプロパティを派生属性に追加できます。

public string RemoteRoles { get; set; }

そして交換

 List<String> requiredRoles = Roles.Split(Convert.ToChar(",")).ToList();

で:

 List<String> requiredRoles = RemoteRoles.Split(Convert.ToChar(",")).ToList();

そして、次のようにコントローラーを飾ります:

[RoleAuthorization (RemoteRoles = "Client, Administrator")]
1
Henry Guillen

MVC 5を使用している場合、DbContextの初期化に次の行を追加して、DbContextで遅延読み込みを有効にする必要があります。

this.Configuration.LazyLoadingEnabled = true;

MVC 5のデフォルトプロジェクトでは、それをApplicationDbContext.csファイルに追加します。

これがMVC 5に固有なのか、Identity 2.0に固有なのか、他のバージョンに影響するのかはわかりません。このセットアップを使用し、遅延読み込みを有効にすると、すべてのデフォルトロールスキーマが機能します。詳細については、 https://stackoverflow.com/a/20433316/2401947 を参照してください。

さらに、ASP.NET Identity 2.0の既定のアクセス許可スキーマを使用している場合、Darrenが述べたようにApplication_AuthenticateRequestを実装する必要はありません。ただし、カスタム認証テーブルを使用している場合は、それも実装する必要があります。

1
fmoliveira