2012-04-26 39 views
6

Tôi đã có một ứng dụng Biểu mẫu web mà tôi đang cố gắng sử dụng bản beta API Web mới với. Các điểm cuối tôi đang hiển thị chỉ nên có sẵn cho người dùng được xác thực của trang web vì họ đang sử dụng AJAX. Trong web.config của tôi, tôi đã thiết lập để từ chối tất cả người dùng trừ khi chúng được xác thực. Điều này hoạt động như nó cần với các biểu mẫu Web nhưng không hoạt động như mong đợi với MVC hoặc API Web.Sử dụng Xác thực Mẫu với Web API

Tôi đã tạo cả Bộ điều khiển MVC và Bộ điều khiển API Web để kiểm tra. Những gì tôi thấy là tôi không thể truy cập vào các điểm cuối MVC hoặc Web API cho đến khi tôi xác thực nhưng sau đó tôi có thể tiếp tục nhấn vào các điểm cuối đó, ngay cả sau khi đóng trình duyệt của tôi và tạo lại nhóm ứng dụng. Nhưng nếu tôi nhấn một trong các trang aspx của tôi, điều này sẽ đưa tôi trở lại trang đăng nhập của mình, thì tôi không thể nhấn vào điểm cuối MVC hoặc API Web cho đến khi tôi xác thực lại.

Có lý do gì khiến MVC và API Web không hoạt động như các trang ASPX của tôi khi phiên của tôi không hợp lệ? Bởi vẻ của nó chỉ có yêu cầu ASPX là xóa cookie xác thực biểu mẫu của tôi, mà tôi giả định là vấn đề ở đây.

+2

Chia sẻ một số cấu hình, mã ... – Aliostad

Trả lời

-1

Nếu bạn đang sử dụng thuộc tính ủy quyền MVC, nó sẽ hoạt động tương tự trên WebAPI như đối với các bộ điều khiển MVC bình thường.

+3

Không, thuộc tính ủy quyền MVC và WebApi hoàn toàn khác nhau. – Jez

3

Nếu API web của bạn chỉ được sử dụng trong một ứng dụng MVC hiện có, lời khuyên của tôi là tạo ra một bộ lọc tùy chỉnh AuthorizeAttribute cho cả MVC và WebAPI điều khiển của bạn; Tôi tạo bộ lọc "AuthorizeSafe", mặc định sẽ liệt kê mọi thứ theo mặc định để nếu bạn quên áp dụng thuộc tính ủy quyền cho bộ điều khiển hoặc phương pháp, bạn bị từ chối truy cập (tôi nghĩ rằng cách tiếp cận danh sách trắng mặc định không an toàn).

Hai lớp thuộc tính được cung cấp để bạn mở rộng; System.Web.Mvc.AuthorizeAttributeSystem.Web.Http.AuthorizeAttribute; trước đây được sử dụng với xác thực biểu mẫu MVC và sau này cũng móc vào xác thực biểu mẫu (điều này rất hay vì nó có nghĩa là bạn không phải xây dựng một kiến ​​trúc xác thực hoàn toàn riêng biệt để xác thực và ủy quyền API của bạn). Dưới đây là những gì tôi đã đưa ra - nó từ chối truy cập vào tất cả các bộ điều khiển/hành động MVC và các bộ điều khiển/hành động WebApi theo mặc định trừ khi áp dụng thuộc tính AllowAnonymous hoặc AuthorizeSafe. Thứ nhất, một phương pháp khuyến nông để giúp đỡ với tùy chỉnh thuộc tính:

public static class CustomAttributeProviderExtensions { 
    public static List<T> GetCustomAttributes<T>(this ICustomAttributeProvider provider, bool inherit) where T : Attribute { 
     List<T> attrs = new List<T>(); 

     foreach (object attr in provider.GetCustomAttributes(typeof(T), false)) { 
      if (attr is T) { 
       attrs.Add(attr as T); 
      } 
     } 

     return attrs; 
    } 
} 

Lớp uỷ quyền helper rằng cả AuthorizeAttribute mở rộng sử dụng:

public static class AuthorizeSafeHelper { 
    public static AuthActionToTake DoSafeAuthorization(bool anyAllowAnonymousOnAction, bool anyAllowAnonymousOnController, List<AuthorizeSafeAttribute> authorizeSafeOnAction, List<AuthorizeSafeAttribute> authorizeSafeOnController, out string rolesString) { 
     rolesString = null; 

     // If AllowAnonymousAttribute applied to action or controller, skip authorization 
     if (anyAllowAnonymousOnAction || anyAllowAnonymousOnController) { 
      return AuthActionToTake.SkipAuthorization; 
     } 

     bool foundRoles = false; 
     if (authorizeSafeOnAction.Count > 0) { 
      AuthorizeSafeAttribute foundAttr = (AuthorizeSafeAttribute)(authorizeSafeOnAction.First()); 
      foundRoles = true; 
      rolesString = foundAttr.Roles; 
     } 
     else if (authorizeSafeOnController.Count > 0) { 
      AuthorizeSafeAttribute foundAttr = (AuthorizeSafeAttribute)(authorizeSafeOnController.First()); 
      foundRoles = true; 
      rolesString = foundAttr.Roles; 
     } 

     if (foundRoles && !string.IsNullOrWhiteSpace(rolesString)) { 
      // Found valid roles string; use it as our own Roles property and auth normally 
      return AuthActionToTake.NormalAuthorization; 
     } 
     else { 
      // Didn't find valid roles string; DENY all access by default 
      return AuthActionToTake.Unauthorized; 
     } 
    } 
} 

public enum AuthActionToTake { 
    SkipAuthorization, 
    NormalAuthorization, 
    Unauthorized, 
} 

Hai lớp học mở rộng bản thân:

public sealed class AuthorizeSafeFilter : System.Web.Mvc.AuthorizeAttribute { 
    public override void OnAuthorization(AuthorizationContext filterContext) { 
     if (!string.IsNullOrEmpty(this.Roles) || !string.IsNullOrEmpty(this.Users)) { 
      throw new Exception("This class is intended to be applied to an MVC web API application as a global filter in RegisterWebApiFilters, not applied to individual actions/controllers. Use the AuthorizeSafeAttribute with individual actions/controllers."); 
     } 

     string rolesString; 
     AuthActionToTake action = AuthorizeSafeHelper.DoSafeAuthorization(
      filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(false).Count() > 0, 
      filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(false).Count() > 0, 
      filterContext.ActionDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>(false), 
      filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>(false), 
      out rolesString 
     ); 

     string rolesBackup = this.Roles; 
     try { 
      switch (action) { 
       case AuthActionToTake.SkipAuthorization: 
        return; 

       case AuthActionToTake.NormalAuthorization: 
        this.Roles = rolesString; 
        base.OnAuthorization(filterContext); 
        return; 

       case AuthActionToTake.Unauthorized: 
        filterContext.Result = new HttpUnauthorizedResult(); 
        return; 
      } 
     } 
     finally { 
      this.Roles = rolesBackup; 
     } 
    } 
} 

public sealed class AuthorizeSafeApiFilter : System.Web.Http.AuthorizeAttribute { 
    public override void OnAuthorization(HttpActionContext actionContext) { 
     if (!string.IsNullOrEmpty(this.Roles) || !string.IsNullOrEmpty(this.Users)) { 
      throw new Exception("This class is intended to be applied to an MVC web API application as a global filter in RegisterWebApiFilters, not applied to individual actions/controllers. Use the AuthorizeSafeAttribute with individual actions/controllers."); 
     } 

     string rolesString; 
     AuthActionToTake action = AuthorizeSafeHelper.DoSafeAuthorization(
      actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0, 
      actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0, 
      actionContext.ActionDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>().ToList(), 
      actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>().ToList(), 
      out rolesString 
     ); 

     string rolesBackup = this.Roles; 
     try { 
      switch (action) { 
       case AuthActionToTake.SkipAuthorization: 
        return; 

       case AuthActionToTake.NormalAuthorization: 
        this.Roles = rolesString; 
        base.OnAuthorization(actionContext); 
        return; 

       case AuthActionToTake.Unauthorized: 
        HttpRequestMessage request = actionContext.Request; 
        actionContext.Response = request.CreateResponse(HttpStatusCode.Unauthorized); 
        return; 
      } 
     } 
     finally { 
      this.Roles = rolesBackup; 
     } 
    } 
} 

Và cuối cùng, thuộc tính có thể được áp dụng cho các phương thức/bộ điều khiển để cho phép người dùng trong một số vai trò nhất định truy cập chúng:

public class AuthorizeSafeAttribute : Attribute { 
    public string Roles { get; set; } 
} 

Sau đó, chúng tôi đăng ký "AuthorizeSafe" của chúng tôi trên toàn cầu bộ lọc từ Global.asax:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) { 
     // Make everything require authorization by default (whitelist approach) 
     filters.Add(new AuthorizeSafeFilter()); 
    } 

    public static void RegisterWebApiFilters(HttpFilterCollection filters) { 
     // Make everything require authorization by default (whitelist approach) 
     filters.Add(new AuthorizeSafeApiFilter()); 
    } 

Sau đó, để mở ra một hành động để ví dụ.truy cập vô danh hoặc chỉ truy cập Quản trị viên:

public class AccountController : System.Web.Mvc.Controller { 
    // GET: /Account/Login 
    [AllowAnonymous] 
    public ActionResult Login(string returnUrl) { 
     // ... 
    } 
} 

public class TestApiController : System.Web.Http.ApiController { 
    // GET API/TestApi 
    [AuthorizeSafe(Roles="Admin")] 
    public IEnumerable<TestModel> Get() { 
     return new TestModel[] { 
      new TestModel { TestId = 123, TestValue = "Model for ID 123" }, 
      new TestModel { TestId = 234, TestValue = "Model for ID 234" }, 
      new TestModel { TestId = 345, TestValue = "Model for ID 345" } 
     }; 
    } 
} 
+0

Anh ấy đang sử dụng biểu mẫu web không phải là mvc ... hoạt động này có giống nhau không? – bbqchickenrobot

+0

@bbqchickenrobot, tôi đã áp dụng giải pháp này cho một dự án Web API thuần túy. Bạn phải bỏ qua một số mã MVC cụ thể. – zacharydl

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