2012-04-26 3 views
6

У меня есть приложение Web Forms, с которым я пытаюсь использовать новую бета-версию Web API. Конечные точки, которые я просматриваю, должны быть доступны только для аутентифицированного пользователя сайта, поскольку они предназначены для использования AJAX. В моем web.config я установил, что он запретил всем пользователям, если они не аутентифицированы. Это работает так же, как и в веб-формах, но не работает с MVC или веб-API.Использование проверки подлинности с помощью веб-API

Я разработал контроллер MVC и контроллер веб-API для тестирования. То, что я вижу, заключается в том, что я не могу получить доступ к конечным точкам MVC или веб-API до тех пор, пока не аутентифицирую, но тогда я могу продолжать удалять эти конечные точки, даже после закрытия моего браузера и повторного использования пула приложений. Но если я удалю одну из моих страниц aspx, которая отправит меня обратно на мою страницу входа в систему, я не могу ударить по конечным точкам MVC или веб-API до тех пор, пока я не аутентифицируюсь снова.

Есть ли причина, по которой MVC и веб-API не работают, поскольку мои страницы ASPX когда-то моя сессия недействительна? По его мнению, только ASPX-запрос очищает мой файл cookie для проверки подлинности форм, который, как я предполагаю, является проблемой здесь.

+2

Share некоторые конфигурации, код ... – Aliostad

ответ

-1

Если вы используете атрибут Authorization MVC, он должен работать таким же образом для WebAPI, как и для обычных контроллеров MVC.

+3

Нет, авторизации MVC атрибуты и WebAPI из них совершенно разные. – Jez

3

Если ваш веб-API используется только в рамках существующего MVC приложения, мой совет, чтобы создать настраиваемый фильтр AuthorizeAttribute для обеих ваших MVC и WebAPI контроллеров; Я создаю то, что я называю фильтром AuthorizeSafe, который черным списком по умолчанию, так что, если вы забудете применить атрибут авторизации к контроллеру или методу, вам будет отказано в доступе (я думаю, что по умолчанию белый список небезопасен).

Два класса атрибутов предназначены для расширения; System.Web.Mvc.AuthorizeAttribute и System.Web.Http.AuthorizeAttribute; первый используется с аутентификацией форм MVC, а второй также подключается к проверке подлинности форм (это очень хорошо, потому что это означает, что вам не нужно создавать целую отдельную архитектуру аутентификации для аутентификации и авторизации API). Вот что я придумал - он запрещает доступ ко всем контроллерам/действиям MVC и контроллерам/действиям WebApi по умолчанию, если не применяется атрибут AllowAnonymous или AuthorizeSafe. Во-первых, метод расширения, чтобы помочь с пользовательскими атрибутами:

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

Помощник авторизации класса, что оба AuthorizeAttribute расширения используют:

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, 
} 

двух классов расширения сами:

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

И наконец, атрибут, который можно применить к методам/контроллерам, чтобы разрешить пользователям в определенных ролях обращаться к ним:

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

Тогда мы регистрируем наши "AuthorizeSafe" фильтры по всему миру от 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()); 
    } 

Затем открыть действие, например, к.анонимный доступ или только администратора доступа:

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

Он использует веб-формы, а не mvc ... это работает одинаково? – bbqchickenrobot

+0

@bbqchickenrobot, я применил это решение к проекту простого веб-API. Вы должны игнорировать часть кода, специфичного для MVC. – zacharydl

Смежные вопросы