Izinkan beberapa peran mengakses tindakan pengontrol

274

Saat ini saya menghias metode seperti ini untuk memungkinkan "anggota" mengakses tindakan pengontrol saya

[Authorize(Roles="members")]

Bagaimana cara saya mengizinkan lebih dari satu peran? Misalnya, berikut ini tidak berfungsi tetapi ini menunjukkan apa yang saya coba lakukan (izinkan akses "anggota" dan "admin"):

[Authorize(Roles="members", "admin")] 
codette
sumber
4
Harap ubah jawaban yang diterima untuk pertanyaan ini. Orang dengan jawaban yang saat ini diterima mengeditnya menunjukkan bahwa dia salah.
Eric J.

Jawaban:

595

Pilihan lain adalah menggunakan filter otorisasi tunggal saat Anda memposting tetapi menghapus kutipan dalam.

[Authorize(Roles="members,admin")]
Jim Schmehil
sumber
5
Bekerja di MVC 5 juga. +1
gkonuralp
4
Bekerja di ASP.NET Core 1.0 (MVC 6) dan Microsoft.AspNet.Identity v3. *
Soren
3
Ini tidak apa-apa jika Anda hanya memiliki satu pengontrol yang perlu Anda otorisasi. Jika Anda memiliki lebih dari satu, Anda menduplikasi konstanta string tersebut (huek). Saya lebih suka kelas statis yang memiliki nama-nama peran. Kebencian hewan peliharaan saya adalah string duplikat ... sangat buruk.
robnick
1
@kraeg kabar baik bahwa Anda memecahkan masalah Anda. Sekarang, pertimbangkan untuk menghapus komentar Anda, tolong
Pablo Claus
1
Mengapa? Butuh waktu lama bagiku untuk menyelesaikan ini. Mungkin bermanfaat bagi orang lain yang mengalami masalah yang sama.
kraeg
129

Jika Anda ingin menggunakan peran khusus, Anda dapat melakukan ini:

CustomRoles kelas:

public static class CustomRoles
{
    public const string Administrator = "Administrador";
    public const string User = "Usuario";
}

Pemakaian

[Authorize(Roles = CustomRoles.Administrator +","+ CustomRoles.User)]

Jika Anda memiliki sedikit peran, mungkin Anda dapat menggabungkannya (untuk kejelasan) seperti ini:

public static class CustomRoles
{
     public const string Administrator = "Administrador";
     public const string User = "Usuario";
     public const string AdministratorOrUser = Administrator + "," + User;  
}

Pemakaian

[Authorize(Roles = CustomRoles.AdministratorOrUser)]
Pablo Claus
sumber
7
Ini akan menjadi jawaban yang baik, jika Anda menjelaskan kepada orang-orang yang tidak tahu apa yang ada di balik CustomRoles.
James Skemp
1
@ JamesSkemp ok, saya telah memperpanjang jawaban saya. Ini sangat sederhana. CustumRoles adalah kelas yang saya buat yang berisi beberapa konstanta, yang sesuai dengan peran aplikasi saya. Saya melakukan itu karena beberapa alasan: 1) Memungkinkan penggunaan intellisense untuk menghindari kesalahan pengejaan 2) Untuk menyederhanakan pemeliharaan. Jika peran berubah, saya harus memperbarui hanya satu tempat di dalam aplikasi saya.
Pablo Claus
@Pabloker Atau Anda dapat membuat enum dengan atribut Flags, misalnya Convert.ToString (CustomRoles.Administrator | CustomRoles.User); - Bagian yang menjengkelkan adalah ini membutuhkan konversi eksplisit
cstruter
Jika Anda memiliki 39 peran?
Kiquenet
Saya pikir masalah Anda berjalan melalui pemodelan izin di luar apa yang dapat dilakukan dengan .net
Pablo Claus
82

Salah satu kemungkinan penyederhanaan adalah dengan subkelas AuthorizeAttribute:

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

Pemakaian:

[Roles("members", "admin")]

Secara semantik itu sama dengan jawaban Jim Schmehil.

Mihkel Müür
sumber
3
Ini tidak berfungsi untuk saya, pengguna yang masuk bisa melewati atribut bahkan jika pengguna tidak memiliki peran apa pun.
Urielzen
9
Jawaban ini lebih baik untuk ketika Anda menggunakan konstanta sebagai nilai Anda: yaitu [Peran (Konstanta.Admin, Konstanta.Pemilik)]
dalcam
3
ini adalah jawaban terbaik
IgorShch
18

Untuk MVC4, menggunakan a Enum( UserRoles) dengan peran saya, saya menggunakan kebiasaan AuthorizeAttribute.

Pada tindakan terkontrol saya, saya lakukan:

[CustomAuthorize(UserRoles.Admin, UserRoles.User)]
public ActionResult ChangePassword()
{
    return View();
}

Dan saya menggunakan kebiasaan AuthorizeAttributeseperti itu:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CustomAuthorize : AuthorizeAttribute
{
    private string[] UserProfilesRequired { get; set; }

    public CustomAuthorize(params object[] userProfilesRequired)
    {
        if (userProfilesRequired.Any(p => p.GetType().BaseType != typeof(Enum)))
            throw new ArgumentException("userProfilesRequired");

        this.UserProfilesRequired = userProfilesRequired.Select(p => Enum.GetName(p.GetType(), p)).ToArray();
    }

    public override void OnAuthorization(AuthorizationContext context)
    {
        bool authorized = false;

        foreach (var role in this.UserProfilesRequired)
            if (HttpContext.Current.User.IsInRole(role))
            {
                authorized = true;
                break;
            }

        if (!authorized)
        {
            var url = new UrlHelper(context.RequestContext);
            var logonUrl = url.Action("Http", "Error", new { Id = 401, Area = "" });
            context.Result = new RedirectResult(logonUrl);

            return;
        }
    }
}

Ini adalah bagian dari FNHMVC yang dimodifikasi oleh Fabricio Martínez Tamayo https://github.com/fabriciomrtnz/FNHMVC/

Bernardo Loureiro
sumber
1
Metode OnAuthorization Anda akan mengharuskan pengguna untuk memiliki semua peran yang disebutkan; apakah itu disengaja, atau apakah Anda melewatkan jeda dalam lingkaran itu?
Tieson T.
@ Tieson: Saya memeriksanya dengan cukup teliti, sepertinya diperlukan istirahat dalam loop itu.
OcelotXL
@ TiesonT. dan @ madrush, saya menghargai perbaikan Anda, itu benar-benar bisa membuat istirahat di dalam loop. Saya akan mengubah kode di atas.
Bernardo Loureiro
Enum UserRoles bagus. Apakah Anda mendeklarasikannya secara manual atau autogenerasi berdasarkan konten DB?
Konrad Viltersten
@KonradViltersten Ini secara manual tapi saya kira dengan Refleksi dan Autogenerated class Dynamic dapat dilakukan
Bernardo Loureiro
3

Solusi lain yang jelas, Anda dapat menggunakan konstanta untuk menjaga konvensi dan menambahkan beberapa atribut [Otorisasi]. Lihat ini:

public static class RolesConvention
{
    public const string Administrator = "Administrator";
    public const string Guest = "Guest";
}

Kemudian di controller:

[Authorize(Roles = RolesConvention.Administrator )]
[Authorize(Roles = RolesConvention.Guest)]
[Produces("application/json")]
[Route("api/[controller]")]
public class MyController : Controller
Renê R. Silva
sumber
14
Beberapa Authorizeatribut menggunakan DAN semantik dan mengharuskan SEMUA kondisi dipenuhi (yaitu pengguna harus berada dalam peran Administrator dan Tamu).
trousyt
3

Jika Anda sering menerapkan 2 peran tersebut, Anda dapat membungkusnya dalam Otorisasi mereka sendiri. Ini benar-benar perpanjangan dari jawaban yang diterima.

using System.Web.Mvc;

public class AuthorizeAdminOrMember : AuthorizeAttribute
{
    public AuthorizeAdminOrMember()
    {
        Roles = "members, admin";
    }
}

Dan kemudian terapkan otorisasi baru Anda ke Action. Saya pikir ini terlihat lebih bersih dan mudah dibaca.

public class MyController : Controller
{
    [AuthorizeAdminOrMember]
    public ActionResult MyAction()
    {
        return null;
    }
}
APK
sumber
1

Kode yang lebih baik dengan menambahkan subkelas AuthorizeRole.cs

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    class AuthorizeRoleAttribute : AuthorizeAttribute
    {
        public AuthorizeRoleAttribute(params Rolenames[] roles)
        {
            this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
        }
        protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAuthenticated)
            {
                filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary {
                  { "action", "Unauthorized" },
                  { "controller", "Home" },
                  { "area", "" }
                  }
              );
                //base.HandleUnauthorizedRequest(filterContext);
            }
            else
            {
                filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary {
                  { "action", "Login" },
                  { "controller", "Account" },
                  { "area", "" },
                  { "returnUrl", HttpContext.Current.Request.Url }
                  }
              );
            }
        }
    }

Cara menggunakan ini

[AuthorizeRole(Rolenames.Admin,Rolenames.Member)]

public ActionResult Index()
{
return View();
}
goel kinzzy
sumber
1

Menggunakan AspNetCore 2.x, Anda harus sedikit berbeda:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class AuthorizeRoleAttribute : AuthorizeAttribute
{
    public AuthorizeRoleAttribute(params YourEnum[] roles)
    {
        Policy = string.Join(",", roles.Select(r => r.GetDescription()));
    }
}

gunakan saja seperti ini:

[Authorize(YourEnum.Role1, YourEnum.Role2)]
Daniel DirtyNative Martin
sumber
-2
Intent promptInstall = new Intent(android.content.Intent.ACTION_VIEW);
promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
promptInstall.setDataAndType(Uri.parse("http://10.0.2.2:8081/MyAPPStore/apk/Teflouki.apk"), "application/vnd.android.package-archive" );

startActivity(promptInstall);
Orsit Moel
sumber
1
Jawaban termasuk kode harus memiliki setidaknya deskripsi minumum yang menjelaskan cara kerja kode dan mengapa ia menjawab pertanyaan. Lebih lanjut, pemformatan bagian kode perlu ditingkatkan.
Roberto Caboni
Hah? @Orsit Moel, Sepertinya disalin-tempel ke urutan yang salah ...
Cameron Forward