web-dev-qa-db-ja.com

asp.net mvc decorate [Authorize()]と複数の列挙型

私にはコントローラーがあり、それにアクセスできるようにするには2つの役割が必要です。 1-admin OR 2-moderator

[Authorize(Roles = "admin、moderators")]を実行できることはわかっていますが、私は列挙型で自分の役割を担っています。列挙型では、1つの役割のみを許可できます。 2つを認証する方法がわかりません。

[Authorize(Roles = MyEnum.Admin、MyEnum.Moderator)]のようなものを試しましたが、コンパイルできません。

誰かがこれを提案しました:

 [Authorize(Roles=MyEnum.Admin)]
 [Authorize(MyEnum.Moderator)]
 public ActionResult myAction()
 {
 }

oRとしては機能しません。この場合、ユーザーは両方の役割の一部である必要があると思います。いくつかの構文を見落としていますか?それとも、独自のカスタム認証をロールバックする必要があるのですか?

34
codette

次のようなビットOR演算子を使用してみてください。

[Authorize(Roles= MyEnum.Admin | MyEnum.Moderator)]
public ActionResult myAction()
{
}

それがうまくいかない場合は、自分でロールすることができます。私は現在、自分のプロジェクトでこれをやっただけです。これが私がしたことです:

public class AuthWhereRole : AuthorizeAttribute
{
    /// <summary>
    /// Add the allowed roles to this property.
    /// </summary>
    public UserRole Is;

    /// <summary>
    /// Checks to see if the user is authenticated and has the
    /// correct role to access a particular view.
    /// </summary>
    /// <param name="httpContext"></param>
    /// <returns></returns>
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
            throw new ArgumentNullException("httpContext");

        // Make sure the user is authenticated.
        if (!httpContext.User.Identity.IsAuthenticated)
            return false;

        UserRole role = someUser.Role; // Load the user's role here

        // Perform a bitwise operation to see if the user's role
        // is in the passed in role values.
        if (Is != 0 && ((Is & role) != role))
            return false;

        return true;
    }
}

// Example Use
[AuthWhereRole(Is=MyEnum.Admin|MyEnum.Newbie)]
public ActionResult Test() {}

また、enumにflags属性を追加し、それらがすべて1以上の値であることを確認してください。このような:

[Flags]
public enum Roles
{
    Admin = 1,
    Moderator = 1 << 1,
    Newbie = 1 << 2
    etc...
}

左ビットシフトは、1、2、4、8、16などの値を与えます。

まあ、これが少し役に立てば幸いです。

31
CalebHC

以下はsimpleでエレガントなソリューションで、次の構文を簡単に使用できます。

[AuthorizeRoles(MyEnum.Admin, MyEnum.Moderator)]

独自の属性を作成する場合は、コンストラクターでparamsキーワードを使用します。

public class AuthorizeRoles : AuthorizeAttribute
{
    public AuthorizeRoles(params MyEnum[] roles)
    {
        ...
    }
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        ...
    }
}

これにより、次のように属性を使用できます。

[AuthorizeRoles(MyEnum.Admin, MyEnum.Moderator)]
public ActionResult myAction()
{
}
37
Zaid Masud

ここでいくつかのソリューションを組み合わせて、個人的なお気に入りを作成しました。私のカスタム属性は、データをSimpleMembershipが予期する形式に変更し、それ以外のすべてを処理できるようにします。

私の役割列挙型:

public enum MyRoles
{
    Admin,
    User,
}

ロールを作成するには:

public static void CreateDefaultRoles()
{
    foreach (var role in Enum.GetNames(typeof(MyRoles)))
    {
       if (!Roles.RoleExists(role))
       {
            Roles.CreateRole(role);
        }
    }
}

カスタム属性:

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    public AuthorizeRolesAttribute(params MyRoles[] allowedRoles)
    {
        var allowedRolesAsStrings = allowedRoles.Select(x => Enum.GetName(typeof(MyRoles), x));
        Roles = string.Join(",", allowedRolesAsStrings);
    }
}

そのように使用:

[AuthorizeRoles(MyRoles.Admin, MyRoles.User)]
public ActionResult MyAction()
{
    return View();
}
8
borigas

試す

public class CustomAuthorize : AuthorizeAttribute
{
    public enum Role
    {
        DomainName_My_Group_Name,
        DomainName_My_Other_Group_Name
    }

    public CustomAuthorize(params Role[] DomainRoles)
    {
        foreach (var domainRole in DomainRoles)
        {
            var domain = domainRole.ToString().Split('_')[0] + "_";
            var role = domainRole.ToString().Replace(domain, "").Replace("_", " ");
            domain=domain.Replace("_", "\\");
            Roles += ", " + domain + role;
        }
        Roles = Roles.Substring(2);
    }       
}

public class HomeController : Controller
{
    [CustomAuthorize(Role.DomainName_My_Group_Name, Role.DomainName_My_Other_Group_Name)]
    public ActionResult Index()
    {
        return View();
    }
}
2
Jay

@CalebHCと@Lee Haroldの回答に基づく私のバージョンを以下に示します。

属性で名前付きパラメーターを使用するスタイルに従い、基本クラスのRolesプロパティをオーバーライドしました。

@CalebHCの回答では、不要な新しいIsプロパティを使用しています。これは、AuthorizeCore()がオーバーライドされるため(基本クラスではRolesを使用するため)、独自のRoles 同じように。独自のRolesを使用して、コントローラーに_Roles = Roles.Admin_を記述します。これは、他の.Net属性のスタイルに従います。

CustomAuthorizeAttributeに2つのコンストラクターを使用して、実際のActive Directoryグループ名が渡されることを示しています。本番環境では、パラメーター化されたコンストラクターを使用して、クラス内のマジック文字列を回避します。グループ名はApplication_Start()およびDIツールを使用して作成時に渡されます。

_NotAuthorized.cshtml_フォルダーに_Views\Shared_または同様のものが必要です。権限のないユーザーにはエラー画面が表示されます。

基本クラス AuthorizationAttribute.cs のコードは次のとおりです。

コントローラ:

_public ActionResult Index()
{
  return this.View();
}

[CustomAuthorize(Roles = Roles.Admin)]
public ActionResult About()
{
  return this.View();
}
_

CustomAuthorizeAttribute:

_// The left bit shifting gives the values 1, 2, 4, 8, 16 and so on.
[Flags]
public enum Roles
{
  Admin = 1,
  User = 1 << 1    
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
  private readonly string adminGroupName;

  private readonly string userGroupName;

  public CustomAuthorizeAttribute() : this("Domain Admins", "Domain Users")
  {      
  }

  private CustomAuthorizeAttribute(string adminGroupName, string userGroupName)
  {
    this.adminGroupName = adminGroupName;
    this.userGroupName = userGroupName;
  }

  /// <summary>
  /// Gets or sets the allowed roles.
  /// </summary>
  public new Roles Roles { get; set; }

  /// <summary>
  /// Checks to see if the user is authenticated and has the
  /// correct role to access a particular view.
  /// </summary>
  /// <param name="httpContext">The HTTP context.</param>
  /// <returns>[True] if the user is authenticated and has the correct role</returns>
  /// <remarks>
  /// This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.
  /// </remarks>
  protected override bool AuthorizeCore(HttpContextBase httpContext)
  {
    if (httpContext == null)
    {
      throw new ArgumentNullException("httpContext");
    }

    if (!httpContext.User.Identity.IsAuthenticated)
    {
      return false;
    }

    var usersRoles = this.GetUsersRoles(httpContext.User);

    return this.Roles == 0 || usersRoles.Any(role => (this.Roles & role) == role);
  }

  protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
  {
    if (filterContext == null)
    {
      throw new ArgumentNullException("filterContext");
    }

    filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
  }

  private IEnumerable<Roles> GetUsersRoles(IPrincipal principal)
  {
    var roles = new List<Roles>();

    if (principal.IsInRole(this.adminGroupName))
    {
      roles.Add(Roles.Admin);
    }

    if (principal.IsInRole(this.userGroupName))
    {
      roles.Add(Roles.User);
    }

    return roles;
  }    
}
_
1
meataxe

CalebHCのコードに追加して、複数の役割を持つユーザーの処理に関するssmithの質問に回答するには...

カスタムセキュリティプリンシパルは、ユーザーが所属するすべてのグループ/ロールを表す文字列配列を返します。そのため、最初に、列挙型の項目に一致する配列内のすべての文字列を変換する必要があります。最後に、一致を探します-一致する場合、ユーザーは承認されます。

権限のないユーザーをカスタムの「NotAuthorized」ビューにリダイレクトすることにも注意してください。

クラス全体は次のようになります。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    /// <summary>
    /// Add the allowed roles to this property.
    /// </summary>
    public Roles Is { get; set; }

    /// <summary>
    /// Checks to see if the user is authenticated and has the
    /// correct role to access a particular view.
    /// </summary>
    /// <param name="httpContext"></param>
    /// <returns></returns>
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
            throw new ArgumentNullException("httpContext");

        if (!httpContext.User.Identity.IsAuthenticated)
            return false;

        var iCustomPrincipal = (ICustomPrincipal) httpContext.User;

        var roles = iCustomPrincipal.CustomIdentity
                        .GetGroups()
                        .Select(s => Enum.Parse(typeof (Roles), s))
                        .ToArray();

        if (Is != 0 && !roles.Cast<Roles>().Any(role => ((Is & role) == role)))
        {
            return false;
        }

        return true;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");

        filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
    } 
}
0
Lee Harold