Özniteliği Birden Çok Rolle Yetkilendirin


100

Aynı anda birden fazla Rol için bir denetleyiciye Yetki eklemek istiyorum.

Normalde bu şöyle görünür:

[Authorize(Roles = "RoleA,RoleB,RoleC")]
public async Task<ActionResult> Index()
{
}

Ancak, bir noktada değişebilecekleri veya genişletilebilecekleri için Rollerimi sabitlerde depoladım.

public const RoleA = "RoleA";
public const RoleB = "RoleB";
public const RoleC = "RoleC";

Dize derleme sırasında bilinmesi gerektiğinden bunu yapamam:

[Authorize(Roles = string.join(",",RoleA,RoleB,RoleC)]
public async Task<ActionResult> Index()
{
}

Sorunu aşmanın bir yolu var mı?

Basitçe "RoleA, RoleB, RoleC" içeren bir const yazabilirim - ama sihirli dizgelerden hoşlanmıyorum ve bu sihirli bir dize. Bir Rolün adını değiştirmek ve birleşik dizeyi değiştirmeyi unutmak felaket olur.

MVC5 kullanıyorum. ASP.NET Kimliği ve Rolü derleme sırasında bilinir.


public const string kullanıyor musunuz RoleA = "RoleA"; veya soruda yazdığınız gibi?
Mukesh Modhvadiya

Yanıtlar:


194

Gibi özel authorize özniteliği oluşturmayı deneyin bu .

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = string.Join(",", roles);
    }
}

Rollerinizin birden çok denetleyici için aynı olacağını varsayarak bir yardımcı sınıf oluşturun:

public static class Role
{
    public const string Administrator = "Administrator";
    public const string Assistant = "Assistant";
}

Öyleyse şu şekilde kullanın:

public class MyController : Controller
{
    [AuthorizeRoles(Role.Administrator, Role.Assistant)]
    public ActionResult AdminOrAssistant()
    {                       
        return View();
    }
}

12
Şimdi bu, Mac Gyver'e layık bir fikir;)
Christian Sauer

2
Çok güzel çözüm :)
aup

1
Bu çözümü de çok seviyorum, özellikle Rolümün bir dizeden ziyade bir sıralama olmasına izin verebildiğim için. Bu özel yetkilendirme özelliğini yerleştirmek için proje hiyerarşisindeki iyi bir ad alanı ve konum ne olabilir?
Simon Shine

4
Burada neler olup bittiğinden emin değilim, ancak bu bana yardımcı OLMADI, rolü ne olursa olsun herhangi bir kullanıcı yönteme erişebildi.
Urielzen

2
@Urielzen ile aynı sorun, ancak Jerry Finegan'ın verdiği yanıtla düzeltildi ("System.Web.Mvc.AuthorizeAttribute ve NOT System.Web.Http.AuthorizeAttribute" kullanılarak)
RJB

13

Emin kapalı özel nitelik sınıf türetmek emin olun System.Web.Mvc.AuthorizeAttributeve DEĞİL System.Web.Http.AuthorizeAttribute.

Ben de aynı problemle karşılaştım. Değiştirdikten sonra her şey işe yaradı.

Ayrıca, özel öznitelik sınıfınıza aşağıdakileri eklemek isteyebilirsiniz:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 

Bunu az önce denedim ve System.Web.Http.AuthorizeAttributeYERİNE kütüphaneye atıfta bulundumSystem.Web.Mvc.AuthorizeAttribute
fraser jordan

13

Bu sorunu çözmek için bulduğum en iyi ve en basit yol, Authorize özniteliğindeki rolleri birleştirmektir.

[Authorize(Roles = CustomRoles.Admin + "," + CustomRoles.OtherRole)]

CustomRole ile aşağıdaki gibi sabit dizelere sahip bir sınıf:

public static class CustomRoles
{
    public const string Admin = "Admin";
    // and so on..
}

2
Değerli; ama bu bir yorum olmalı; cevap değil.
GhostCat

1
Basit ve zarif çözüm!
Iosif Bancioiu

Doğru uygulandığında hem cevabınız hem de kabul edilen cevap yetkilendirmeyi tetikleyecektir (bir üretim web uygulamasında kabul edileni kullanıyorum). Kabul edilen cevapla ilgili yorumları kaldırmak için bir düzenleme önermek.
Eric Eskildsen

Roller Enum ise, [Authorize (Roles = nameof (UserRoleEnum.User) + "," + nameof (UserRoleEnum.Admin))]
Varun

3

Yaptığım şey @ Tieson'daki cevap

Cevabında biraz ince ayar yaptım. String yerine.join neden listeye dönüştürmüyorsunuz?

İşte cevabım:

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    private new List<string> Roles;
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = roles.toList()
    }
}

Ardından, rolün OnAuthorization'ı geçersiz kılarak geçerli olup olmadığını kontrol edin.

public override void OnAuthorization(HttpActionContext actionContext)
{
            if (Roles == null)
                HandleUnauthorizedRequest(actionContext);
            else
            {
                ClaimsIdentity claimsIdentity = HttpContext.Current.User.Identity as ClaimsIdentity;
                string _role = claimsIdentity.FindFirst(ClaimTypes.Role).Value;
                bool isAuthorize = Roles.Any(role => role == _role);

                if(!isAuthorize)
                    HandleUnauthorizedRequest(actionContext);
            }
        }

Ve işte var, şimdi rolün kaynağa erişmeye yetkili olup olmadığını doğruluyor


1

Çok sayıda rolünüz yoksa özel bir yetkilendirme özelliğinin bu sorun için gereğinden fazla olduğunu düşünüyorum.

Dizenin derleme zamanında bilinmesi gerektiğinden, neden tanımladığınız rollerin genel dizelerini içeren statik bir Rol sınıfı oluşturup ardından yetkilendirmek istediğiniz belirli rollere sahip virgülle ayrılmış dizeler eklemiyorsunuz:

public static class Roles
{
    public const string ADMIN = "Admin";
    public const string VIEWER = "Viewer";

    public const string ADMIN_OR_VIEWER = ADMIN + "," + VIEWER;
}

Ve sonra Yetkilendirme Özniteliğini Denetleyici Sınıfı veya Denetleyici Yönteminde (veya her ikisinde) olduğu gibi kullanabilirsiniz:

[Authorize(Roles = Roles.ADMIN]
public class ExampleController : Controller
{
    [Authorize(Roles = Roles.ADMIN_OR_VIEWER)
    public ActionResult Create()
    {
        ..code here...
    }
}

1
Bu örnek işe yaramıyor veya en azından düşündüğünüz şekilde değil. Örneğin, yeni iken ADMIN_OR_VIEWER, eylemdeki rol gereksizdir çünkü Createzaten ADMINrolünüz yoksa yönteme girmenize izin verilmeyecektir . Bu durumda VIEWERasla Createyöntemi çağıramayacaktır .
John Leidegren

Bu çözüm de ölçeklenebilir değil. Farklı eylemlerle çok fazla
rolünüzün olduğu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.