91

Tôi đang tạo trang web nhiều người thuê nhà lưu trữ các trang cho khách hàng. Các phân đoạn đầu tiên của URL sẽ là một chuỗi trong đó xác định các khách hàng, quy định tại Global.asax sử dụng thức truy cập URL định tuyến sau:Cách chuyển hướng đến URL đăng nhập động trong ASP.NET MVC

"{client}/{controller}/{action}/{id}" 

này hoạt động tốt, với URL như/foo/Home/Index.

Tuy nhiên, khi sử dụng thuộc tính [Ủy quyền], tôi muốn chuyển hướng đến trang đăng nhập cũng sử dụng cùng một lược đồ ánh xạ. Vì vậy, nếu khách hàng là foo, trang đăng nhập sẽ là/foo/Tài khoản/Đăng nhập thay vì chuyển hướng/Tài khoản/Đăng nhập cố định được xác định trong web.config.

MVC sử dụng HttpUnauthorizedResult để trả lại trạng thái không được phép 401, mà tôi cho là nguyên nhân ASP.NET chuyển hướng đến trang được xác định trong web.config.

Vì vậy, có ai biết cách ghi đè hành vi chuyển hướng đăng nhập ASP.NET không? Hoặc nó sẽ là tốt hơn để chuyển hướng trong MVC bằng cách tạo một thuộc tính ủy quyền tùy chỉnh?

EDIT - Trả lời: sau khi một số đào vào nguồn Net, tôi quyết định rằng một thuộc tính xác thực tùy chỉnh là giải pháp tốt nhất:

public class ClientAuthorizeAttribute: AuthorizeAttribute 
{ 
    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     base.OnAuthorization(filterContext); 

     if (filterContext.Cancel && filterContext.Result is HttpUnauthorizedResult) 
     { 
      filterContext.Result = new RedirectToRouteResult(
       new RouteValueDictionary 
       { 
        { "client", filterContext.RouteData.Values[ "client" ] }, 
        { "controller", "Account" }, 
        { "action", "Login" }, 
        { "ReturnUrl", filterContext.HttpContext.Request.RawUrl } 
       }); 
     } 
    } 
} 
+2

làm gần như chính xác những điều tương tự với định tuyến, vì vậy tôi cần thiết này! Cảm ơn! –

+0

Cảm ơn, tôi đã cố gắng tìm ra cách để làm một cái gì đó tương tự. – Chance

+0

nó đã cho tôi ý tưởng để thực hiện riêng, cảm ơn rất nhiều! –

Trả lời

30

Tôi nghĩ vấn đề chính ở đây là nếu bạn đang đi để piggyback trên được xây dựng trong ASP.NET FormsAuthentication lớp (và không có lý do tốt bạn không nên), một cái gì đó vào cuối ngày sẽ gọi FormsAuthentication.RedirectToLoginPage() mà sẽ xem xét một URL cấu hình. Chỉ có một URL đăng nhập, và đó chỉ là cách họ thiết kế nó.

Lỗi của tôi về sự cố (có thể là triển khai Rube Goldberg) sẽ cho phép chuyển hướng đến một trang đăng nhập duy nhất tại thư mục gốc được chia sẻ bởi tất cả khách hàng, nói/account/login. Trang đăng nhập này sẽ không hiển thị bất kỳ thứ gì; nó kiểm tra tham số ReturnUrl hoặc một số giá trị tôi có trong phiên hoặc cookie xác định khách hàng và sử dụng nó để phát hành chuyển hướng 302 ngay lập tức đến trang/khách hàng/tài khoản/đăng nhập cụ thể. Đó là một chuyển hướng phụ, nhưng có thể không đáng chú ý và nó cho phép bạn sử dụng các cơ chế chuyển hướng được xây dựng.

Tùy chọn khác là tạo thuộc tính tùy chỉnh của riêng bạn khi bạn mô tả và tránh bất kỳ thứ gì gọi phương thức RedirectToLoginPage() trên lớp FormsAuthentication, vì bạn sẽ thay thế nó bằng logic chuyển hướng của riêng bạn. (Bạn có thể tạo lớp của riêng bạn tương tự.) Vì đó là một lớp tĩnh, tôi không biết về bất kỳ cơ chế nào mà bạn có thể tiêm giao diện thay thế của riêng bạn và làm việc với thuộc tính [Authorize] hiện có, thổi, nhưng people have done similar things before.

Hy vọng điều đó sẽ hữu ích!

+0

đây có lẽ là cách tiếp cận an toàn nhất. việc tạo thuộc tính [MyAuthorize] của riêng bạn là nguy hiểm. trừ khi tòa nhà của bạn xác minh rằng mọi người không sử dụng thuộc tính [Authorize] tích hợp mà bạn có nguy cơ (hoặc chính bạn) quên và sử dụng sai số –

40

Trong phiên bản RTM của ASP.NET MVC, thuộc tính Hủy bị thiếu. Mã này làm việc với ASP.NET MVC RTM:

using System; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Mvc.Resources; 

namespace ePegasus.Web.ActionFilters 
{ 
    public class CustomAuthorize : AuthorizeAttribute 
    { 
     public override void OnAuthorization(AuthorizationContext filterContext) 
     { 
      base.OnAuthorization(filterContext); 
      if (filterContext.Result is HttpUnauthorizedResult) 
      { 
       filterContext.Result = new RedirectToRouteResult(
        new System.Web.Routing.RouteValueDictionary 
         { 
           { "langCode", filterContext.RouteData.Values[ "langCode" ] }, 
           { "controller", "Account" }, 
           { "action", "Login" }, 
           { "ReturnUrl", filterContext.HttpContext.Request.RawUrl } 
         }); 
      } 
     } 
    } 
} 

Edit: Bạn có thể muốn vô hiệu hóa các loginUrl hình thức mặc định xác thực trong web.config - trong trường hợp ai đó quên bạn có một thuộc tính tùy chỉnh và sử dụng được xây dựng trong [Authorize] thuộc tính do nhầm lẫn.

Sửa đổi giá trị trong web.config:

<forms loginUrl="~/Account/ERROR" timeout="2880" /> 

Sau đó, tạo phương thức hành động 'ERROR' để ghi lỗi và chuyển hướng người dùng đến trang đăng nhập chung nhất mà bạn có.

+2

hãy đảm bảo thêm {area, null} vào từ điển (hoặc bất kỳ khu vực nào của bạn) được gọi) nếu sử dụng MVC 2 trở lên - nếu không nó sẽ được kế thừa từ trang bạn đã cố truy cập –

2

Giải pháp của tôi cho vấn đề này là một tùy chỉnh ActionResult lớp:

sealed public class RequiresLoginResult : ActionResult 
    { 
     override public void ExecuteResult (ControllerContext context) 
     { 
      var response = context.HttpContext.Response; 

      var url = FormsAuthentication.LoginUrl; 
      if (!string.IsNullOrWhiteSpace (url)) 
       url += "?returnUrl=" + HttpUtility.UrlEncode (ReturnUrl); 

      response.Clear(); 
      response.StatusCode = 302; 
      response.RedirectLocation = url; 
     } 

     public RequiresLoginResult (string returnUrl = null) 
     { 
      ReturnUrl = returnUrl; 
     } 

     string ReturnUrl { get; set; } 
    } 
Các vấn đề liên quan