Ủy quyền thuộc tính với nhiều vai trò


97

Tôi muốn thêm Ủy quyền vào bộ điều khiển, cho nhiều Vai trò cùng một lúc.

Thông thường nó sẽ trông như thế này:

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

Nhưng tôi đã lưu trữ các Vai trò của mình trong bảng điều khiển, vì chúng có thể thay đổi hoặc được mở rộng vào một thời điểm nào đó.

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

Tôi không thể làm điều này, vì chuỗi phải được biết tại thời điểm biên dịch:

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

Có cách nào để vượt qua vấn đề?

TÔI CÓ THỂ viết một const chỉ đơn giản chứa "RoleA, RoleB, RoleC" - nhưng tôi không thích chuỗi ma thuật và đây là một chuỗi ma thuật. Thay đổi tên của một Vai trò và quên thay đổi chuỗi kết hợp sẽ là một thảm họa.

Tôi đang sử dụng MVC5. ASP.NET Identity và Role được biết đến tại thời điểm biên dịch.


bạn có đang sử dụng public const string RoleA = "RoleA" không; hoặc như bạn đã viết trong câu hỏi?
Mukesh Modhvadiya

Câu trả lời:


188

Cố gắng tạo thuộc tính ủy quyền tùy chỉnh như thế này .

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

Giả sử các vai trò của bạn sẽ giống nhau đối với nhiều bộ điều khiển, hãy tạo một lớp trợ giúp:

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

Sau đó, sử dụng nó như vậy:

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

12
Bây giờ đó là một ý tưởng xứng đáng với Mac Gyver;)
Christian Sauer

2
Giải pháp rất hay :)
aup 24/09/15

1
Tôi cũng rất thích giải pháp này, đặc biệt là vì tôi có thể để Vai trò của mình là một enum hơn là một chuỗi. Một không gian tên và vị trí tốt trong hệ thống phân cấp dự án sẽ như thế nào để đặt thuộc tính ủy quyền tùy chỉnh này?
Simon Shine

4
Tôi không chắc điều gì đang xảy ra ở đây, nhưng điều này KHÔNG giúp được gì cho tôi, bất kỳ người dùng nào bất kể vai trò gì đều có thể truy cập phương thức.
Urielzen

2
Cùng một vấn đề với @Urielzen, nhưng nó đã được khắc phục bằng câu trả lời bên dưới từ Jerry Finegan (sử dụng "System.Web.Mvc.AuthorizeAttribute và NOT System.Web.Http.AuthorizeAttribute")
RJB

13

Đảm bảo rằng bạn đang lấy ra lớp thuộc tính tùy chỉnh của mình System.Web.Mvc.AuthorizeAttributevà KHÔNG System.Web.Http.AuthorizeAttribute.

Tôi đã gặp phải vấn đề tương tự. Một khi tôi thay đổi nó, mọi thứ đều hoạt động.

Bạn cũng có thể muốn thêm phần sau vào lớp thuộc tính tùy chỉnh của mình:

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

Tôi vừa thử cái này và thấy đang tham khảo thư viện System.Web.Http.AuthorizeAttributeINSTEAD OFSystem.Web.Mvc.AuthorizeAttribute
fraser jordan,

10

Cách tốt nhất và đơn giản nhất mà tôi tìm thấy để giải quyết vấn đề này là chỉ nối các vai trò trong thuộc tính Authorize.

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

với CustomRole một lớp có các chuỗi không đổi như thế này:

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

2
Có giá trị; nhưng đây phải là một bình luận; không phải là một câu trả lời.
GhostCat

1
Giải pháp đơn giản và thanh lịch!
Iosif Bancioiu

Cả câu trả lời của bạn và câu trả lời được chấp nhận sẽ kích hoạt ủy quyền nếu được triển khai đúng cách (Tôi đang sử dụng câu trả lời được chấp nhận trong ứng dụng web sản xuất). Đề xuất chỉnh sửa để loại bỏ các nhận xét về câu trả lời được chấp nhận.
Eric Eskildsen

3

Những gì tôi đã làm là câu trả lời trong @Tieson

Tôi chỉnh sửa một chút trong câu trả lời của anh ấy. Thay vì string.Join tại sao không chuyển nó thành list?

Đây là câu trả lời của tôi:

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

Và sau đó kiểm tra xem vai trò có hợp lệ ghi đè OnAuthorization hay không

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);
            }
        }

Và bạn đã có nó, nó hiện đang xác thực nếu vai trò được phép truy cập tài nguyên


1

Tôi cảm thấy như thuộc tính ủy quyền tùy chỉnh là quá mức cần thiết cho vấn đề này trừ khi bạn có một lượng lớn vai trò.

Vì chuỗi phải được biết tại thời điểm biên dịch, tại sao không tạo một lớp Vai trò tĩnh chứa các chuỗi công khai của các vai trò bạn đã xác định, sau đó thêm các chuỗi được phân tách bằng dấu phẩy với các vai trò nhất định mà bạn muốn cho phép:

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

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

Và sau đó, bạn có thể sử dụng Thuộc tính ủy quyền tương tự như vậy trên Lớp bộ điều khiển hoặc Phương thức bộ điều khiển (hoặc cả hai):

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

1
Ví dụ này không hoạt động, hoặc ít nhất không phải theo cách bạn có thể nghĩ. Ví dụ, trong khi làm mới ADMIN_OR_VIEWERvai trò trên hành động là thừa vì bạn sẽ không được phép thực hiện Createphương pháp nếu bạn chưa có ADMINvai trò đó. Trong trường hợp VIEWERnày sẽ không bao giờ có thể gọi Createphương thức.
John Leidegren

Giải pháp này cũng không thể mở rộng. Sẽ có một điểm mà bạn có quá nhiều vai trò với hành động khác nhau và bạn không nên tạo mọi sự kết hợp
EduLopez
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.