2010-02-04 35 views
15

Vì vậy, tôi đã đọc một câu hỏi khác liên quan đến vòng đăng nhập khi bạn có người dùng đăng nhập, đặt trở về URL mà họ có thể không có quyền truy cập sau khi đăng nhập (ví dụ: trang quản trị và người dùng đăng nhập bằng thông thường tài khoản).ASP.Net MVC cách xác định xem người dùng có thể truy cập URL không?

Giải pháp trong WebForms có vẻ là sử dụng phương pháp UrlAuthorizationModule.CheckUrlAccessForPrincipal. Tuy nhiên, điều đó không hoạt động đối với các URL đi đến các Phương thức hành động được bảo mật với Thuộc tính ủy quyền. Tôi nghĩ rằng tôi có thể tìm ra phương thức mà URL trỏ đến và phản ánh nó để giải quyết vấn đề của tôi - nhưng dường như tôi không thể tìm ra cách để lấy thông tin này ra khỏi bảng định tuyến.

Bất cứ ai từng làm việc với điều này hoặc có giải pháp cho điều này? Nếu tôi chỉ có thể nắm giữ thông tin tuyến đường từ một URL, tôi nghĩ rằng tôi có thể làm việc phần còn lại ra, nhưng nếu có ai có một giải pháp chung chung - tức là. một số phương pháp ẩn giống như một phương pháp đã được đề cập trước đó cho MVC, thì điều đó cũng hoàn toàn tuyệt vời.

Tôi không hỏi cách kiểm tra xem Người dùng đã truy cập vào cặp Bộ điều khiển/Hành động được chỉ định. Trước tiên, tôi cần phải tìm hiểu cách để có được cặp Controller/Action từ RouteTable dựa trên URL. Lý do cho tất cả các câu chuyện nền, là trong trường hợp có thực sự tồn tại tương đương với UrlAuthorizationModule.CheckUrlAccessForPrincipal cho MVC.

Trả lời

1

vấn đề bạn đang cố gắng để giải quyết là gì? Có vẻ như bạn có thể đi xuống một con đường dẫn đến một giải pháp phức tạp có thể sử dụng một giải pháp đơn giản thay thế.

Nếu người dùng không có quyền truy cập trang sau khi đăng nhập, bạn có muốn người dùng không đăng nhập truy cập vào một trang hay không, trong khi người dùng đã đăng nhập truy cập trang khác?

Nếu đó là trường hợp tôi có thể bị cám dỗ để tạo bộ điều khiển khác cho các trường hợp như vậy và chuyển hướng đến bộ điều khiển đó ở bất kỳ nơi nào người dùng không có quyền truy cập. Hoặc nếu bạn đang sử dụng bộ điều khiển cơ bản của riêng mình, tôi sẽ đặt chức năng ở đó.

Sau đó, trình điều khiển có thể trình bày chế độ xem mong muốn. Ví dụ: nếu người dùng không đăng nhập cố gắng truy cập trang, họ có thể bị chuyển hướng đến trang lỗi chung. Nếu người dùng đăng nhập, họ có thể được chuyển hướng đến một trang không được ủy quyền.

Điều này rất giống với câu trả lời của Robert.

Đây là bộ xương cơ bản cho bộ điều khiển cơ sở.

public BaseController: Controller 
{ 

... // Some code 

    public ActionResult DisplayErrorPage() 
    { 
     // Assumes you have a User object with a IsLoggedIn property 
     if (User.IsLoggedIn())  
      return View("NotAuthorized"); 

     // Redirect user to login page 
     return RedirectToAction("Logon", "Account"); 
    } 

} 

Sau đó, trong phép nói một AdminController (được thừa kế từ BaseController) hành động

public ActionResult HighlyRestrictedAction() 
{ 
    // Assumes there is a User object with a HasAccess property 
    if (User.HasAccess("HighlyRestrictedAction") == false) 
     return DisplayErrorPage(); 

    // At this point the user is logged in and has permissions 
    ... 
} 
+0

Tôi sẽ chấp nhận điều này bây giờ vì nó có vẻ là giải pháp tốt nhất cho dơi ngay bây giờ. Tôi không chắc chắn tôi sẽ thực sự sử dụng điều này mặc dù.Tôi thực sự thích ý tưởng không phải có loại logic này được nhúng vào bộ điều khiển của tôi - tôi cũng muốn tránh chuyển hướng thêm. – kastermester

1

này có lẽ sẽ âm thanh gây nhiều tranh cãi, nhưng tôi kiểm tra an ninh tại đầu mỗi phương pháp điều khiển, bên trong phương pháp:

public class ProductController : Controller 
{ 
    IProductRepository _repository 

    public ActionResult Details(int id) 
    { 
     if(!_repository.UserHasAccess(id)) 
      return View("NotAuthorized"); 

     var item = _repository.GetProduct(id); 

     if (item == null) 
      return View("NotFound"); 

     return View(item); 
    } 
} 

Lý do tôi không sử dụng các [Authorize] thuộc tính cho điều này là bạn không thể chuyển id hoặc bất kỳ thông tin nhận dạng nào khác vào thuộc tính khi chạy.

+0

Cảm ơn, nhưng tôi không chắc cách thức tiếp cận này sẽ giúp tôi - xem các nhận xét tôi đã để lại cho jfar. – kastermester

5

tôi chuyển và hack mã này từ MvcSitemap:

public static class SecurityTrimmingExtensions 
{ 

    /// <summary> 
    /// Returns true if a specific controller action exists and 
    /// the user has the ability to access it. 
    /// </summary> 
    /// <param name="htmlHelper"></param> 
    /// <param name="actionName"></param> 
    /// <param name="controllerName"></param> 
    /// <returns></returns> 
    public static bool HasActionPermission(this HtmlHelper htmlHelper, string actionName, string controllerName) 
    { 
     //if the controller name is empty the ASP.NET convention is: 
     //"we are linking to a different controller 
     ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName) 
               ? htmlHelper.ViewContext.Controller 
               : GetControllerByName(htmlHelper, controllerName); 

     var controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerToLinkTo); 

     var controllerDescriptor = new ReflectedControllerDescriptor(controllerToLinkTo.GetType()); 

     var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName); 

     return ActionIsAuthorized(controllerContext, actionDescriptor); 
    } 


    private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
    { 
     if (actionDescriptor == null) 
      return false; // action does not exist so say yes - should we authorise this?! 

     AuthorizationContext authContext = new AuthorizationContext(controllerContext); 

     // run each auth filter until on fails 
     // performance could be improved by some caching 
     foreach (IAuthorizationFilter authFilter in actionDescriptor.GetFilters().AuthorizationFilters) 
     { 
      authFilter.OnAuthorization(authContext); 

      if (authContext.Result != null) 
       return false; 
     } 

     return true; 
    } 

    private static ControllerBase GetControllerByName(HtmlHelper helper, string controllerName) 
    { 
     // Instantiate the controller and call Execute 
     IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory(); 

     IController controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName); 

     if (controller == null) 
     { 
      throw new InvalidOperationException(

       String.Format(
        CultureInfo.CurrentUICulture, 
        "Controller factory {0} controller {1} returned null", 
        factory.GetType(), 
        controllerName)); 

     } 

     return (ControllerBase)controller; 
    } 

Nó có thể sử dụng một số bộ nhớ đệm nhưng đối với trường hợp của tôi đó là một tối ưu hóa quá sớm.

+0

Vấn đề của tôi là tôi có một URL, không phải là một bộ điều khiển và một hành động. Mã bạn đã viết ở đây là những thứ tôi tin rằng tôi có thể tự nấu ăn - mặc dù cảm ơn vì đã chia sẻ nó vì tôi có thể sẽ cần một cái gì đó như thế này. Nhưng câu hỏi đặt ra là - làm thế nào để tôi có được Controller + Action được tách ra khỏi RouteTable từ một URL? Lý do tại sao tôi đã viết rất nhiều về những thứ khác là bởi vì tôi đã nghi ngờ rằng có thể thực sự có một phương pháp để gọi cho tôi biết tất cả điều này trong 1 đi. – kastermester

+0

@kastermester: Để thực hiện điều đó, bạn sẽ phải chặn yêu cầu trước khi phương thức điều khiển được thực hiện. Để có ý tưởng về cách thực hiện việc này, hãy xem tại đây: http://stackoverflow.com/questions/2122459/how-malleable-are-the-conventions-in-asp-net-mvc/2122521#2122521 –

+0

Chỉ cần những gì tôi cần. Tôi đã tìm kiếm cao và thấp cho cái này. Cảm ơn rất nhiều! –

0

Tại sao không thuộc tính các phương thức điều khiển của bạn với yêu cầu bảo mật.

tôi đã viết một thuộc tính để làm điều này như sau:

public class RequiresRoleAttribute : ActionFilterAttribute 
     { 
      public string Role { get; set; } 

      public override void OnActionExecuting(ActionExecutingContext filterContext) 
      { 
       if (string.IsNullOrEmpty(Role)) 
       { 
        throw new InvalidOperationException("No role specified."); 
       } 


       if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
       { 
        filterContext.HttpContext.Response.Redirect(loginUrl, true); 
       } 
       else 
       { 
        bool isAuthorised = filterContext.HttpContext.User.IsInRole(this.Role); 

        << Complete Logic Here >> 



       } 
      }  
     } 
+0

Vấn đề của tôi là: Người dùng truy cập trang đăng nhập của tôi. Khi nhập một url "return" được thiết lập và được thực hiện trong chuỗi truy vấn. Giả sử trong giây lát rằng bằng cách nào đó URL đó trỏ đến phần quản trị của trang web. Người dùng đăng nhập - bằng tài khoản bình thường. Bây giờ sử dụng loại mã này (mà tôi) người dùng sẽ được chuyển hướng đến trang đăng nhập - nhưng anh ấy đã đăng nhập! Tôi chỉ có thể chuyển hướng đến trang mặc định - nhưng sau đó mọi người sẽ đến đó - cũng là những người chưa được xác thực. Tôi rất muốn xác minh điều này trước khi chuyển hướng sau khi đăng nhập. – kastermester

1

Trong ứng dụng của tôi, tôi đã tạo ra một bộ lọc tùy biến bắt nguồn từ AuthorizeAttribute, vì vậy bất kỳ truy cập trái phép sẽ đơn giản đi đến trang AccessDenied . Đối với các liên kết, tôi thay thế Html.ActionLink bằng một trình trợ giúp tùy chỉnh Html.SecureLink. Trong phần mở rộng của trình trợ giúp này, tôi kiểm tra vai trò của người dùng này đối với bộ điều khiển/hành động đối với cơ sở dữ liệu. Nếu anh ấy/cô ấy có sự cho phép, trở về liên kết khác trả lại văn bản liên kết với bài phát biểu đặc biệt (có thể là hình ảnh/màu/js) câu trả lời

8

jfar của trên được cập nhật cho MVC 4:

public static class SecurityCheck 
{ 
    public static bool ActionIsAuthorized(string actionName, string controllerName) 
    { 
     IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory(); 
     ControllerBase controller = factory.CreateController(HttpContext.Current.Request.RequestContext, controllerName) as ControllerBase; 
     var controllerContext = new ControllerContext(HttpContext.Current.Request.RequestContext, controller); 
     var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType()); 
     var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName); 
     AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor); 
     foreach (var authAttribute in actionDescriptor.GetFilterAttributes(true).Where(a => a is AuthorizeAttribute).Select(a => a as AuthorizeAttribute)) 
     { 
      authAttribute.OnAuthorization(authContext); 
      if (authContext.Result != null) 
       return false; 
     } 
     return true; 
    } 
} 
+0

Hoặc "foreach (var authAttribute in actionDescriptor.GetFilterAttributes (true) .OfType ())" - với lời xin lỗi cho người đi bộ. –

0

tôi chỉ cần bỏ ra một số thời gian thực hiện giải pháp @ jfar (cập nhật nó cho phiên bản GetFilters không được dùng nữa), và sau đó tôi nhận ra rằng tôi có thể bỏ qua toàn bộ điều này.

trong trường hợp của tôi (và tôi giả định hầu hết các trường hợp) Tôi có một AuthorizationAttribute tùy chỉnh để triển khai ủy quyền trang web, lần lượt gọi dịch vụ ủy quyền của tôi để thực hiện xác định cấp truy cập thực tế.

Vì vậy, trong helper html của tôi để tạo ra các liên kết đơn, tôi bỏ qua quyền dịch vụ auth:

@Html.MenuItem(@Url, "icon-whatever", "TargetController", "TargetAction") 

public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper, UrlHelper url,string iconCss, string targetController, string targetAction) 
{ 
    var auth = IoC.Resolve<IClientAuthorizationService>().Authorize(targetController, targetAction); 
    if (auth == AccessLevel.None) 
     return MvcHtmlString.Create(""); 

* sử dụng được xác định trong dịch vụ khách hàng auth

public string GetUser() { 
    return HttpContext.Current.User.Identity.Name; 
} 

* cũng có thể thêm một số hành vi cho quyền truy cập chỉ đọc. nó là tốt đẹp bởi vì dịch vụ auth của tôi chăm sóc bộ nhớ đệm vì vậy tôi không phải lo lắng về hiệu suất.

Các vấn đề liên quan