2012-02-22 7 views
5

У меня есть служба восстановления ASP MVC3, использующая базовую аутентификацию. После поиска переполнения стека я создал следующий код.asp mvc 3 ActionFilter для базовой аутентификации

public class BasicAuthentication : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     var req = filterContext.HttpContext.Request; 
     if (String.IsNullOrEmpty(req.Headers["Authorization"])) 
     { 
      filterContext.Result = new HttpNotFoundResult(); 
     } 
     else 
     { 
      var credentials = System.Text.ASCIIEncoding.ASCII 
         .GetString(Convert.FromBase64String(req.Headers["Authorization"].Substring(6))) 
         .Split(':'); 
      var user = new { Name = credentials[0], Password = credentials[1] }; 
      if(!(user.Name == "username" && user.Password == "passwords")) 
      { 
       filterContext.Result = new HttpNotFoundResult(); 
      } 
     } 
    } 
} 

1) Является ли ActionFilterAttribute лучшим способом для этого?

2) Установлен фильтрContext.Result правильный способ запретить доступ к методу контроллера?

3) Есть ли что-нибудь, что я делаю неправильно?

Спасибо.

-Nick

+0

вы используете основной для форм/пользовательского типа AUTH с базовым (двухступенчатый AUTH) или все-таки с помощью учетных записей домена? –

ответ

12

1) Является ActionFilterAttribute лучший способ сделать это?
думаю. Этот подход отражает реализацию встроенного атрибута Authorize.

2) Устанавливает filterContext.Result правильный способ запретить доступ к методу контроллера?
Да. Для чего это нужно. (1)

3) Есть ли что-нибудь, что я делаю неправильно?

  • Вы предполагаете, что содержание заголовка Authorization находится в правильном формате и правильно закодированы.
  • Вы предполагаете, что запрос предназначен для базовой аутентификации, а не для любой другой схемы аутентификации .
  • Я бы предпочел использовать HttpUnauthorizedResult(), чтобы отправить сообщение об ошибке вместо ошибки http 404 через HttpNotFoundResult().

Ниже в моей реализации вашего кода (который, я уверен, тоже имеет свои проблемы).

public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     try 
     { 
      if (String.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["Authorization"])) 
      { 
       filterContext.Result = new HttpUnauthorizedResult(); 
      } 
      else 
      { 
       if (filterContext.HttpContext.Request.Headers["Authorization"].StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase)) 
       { 
        string[] credentials = ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(filterContext.HttpContext.Request.Headers["Authorization"].Substring(6))).Split(':'); 

        if (credentials.Length == 2) 
        { 
         if (String.IsNullOrEmpty(credentials[0])) 
         { 
          filterContext.Result = new HttpUnauthorizedResult(); 
         } 
         else if (!(credentials[0] == "username" && credentials[1] == "passwords")) 
         { 
          filterContext.Result = new HttpUnauthorizedResult(); 
         } 
        } 
        else 
        { 
         filterContext.Result = new HttpUnauthorizedResult(); 
        } 
       } 
       else 
       { 
        filterContext.Result = new HttpUnauthorizedResult(); 
       } 
      } 

      base.OnActionExecuting(filterContext); 
     } 
     catch 
     { 
      filterContext.Result = new HttpUnauthorizedResult(); 
     } 
    } 

Примечание

  • Я не включил незаконные проверки символов для имени пользователя и пароля.
  • Я не мог решить, как реализовать обработку исключений, поэтому я пошел с простотой.

Ссылки

(1) http://msdn.microsoft.com/en-us/magazine/gg232768.aspx

-2

1) Нет, атрибуты ActionFilter не хороший подход к аутентификации пользователя. (как нам нужно для проверки подлинности один раз и установить подлинность куки, так HttpContext.User будет оставаться аутентифицирован до печенья истекает)

2) Да, установка filtercontext.Result является идеальным способом для предотвращения доступа. (Но вместо назначения HttpNotFoundResult используйте RedirectResult для перенаправления на страницу входа)

3) Я действительно не понимаю, почему такая реализация для авторизации. Лучшим подходом было бы иметь действие, которое будет получать данные, размещенные в форме (имя пользователя и пароль). и используйте атрибут Authorize для предотвращения несанкционированного доступа.

следующий код из примера применения MVC3 по умолчанию в VS2010.

[HttpPost] 
    public ActionResult LogOn(LogOnModel model, string returnUrl) 
    { 
     if (ModelState.IsValid) 
     { 
      if (Membership.ValidateUser(model.UserName, model.Password)) 
      { 
       FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); 
       if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") 
        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) 
       { 
        return Redirect(returnUrl); 
       } 
       else 
       { 
        return RedirectToAction("Index", "Home"); 
       } 
      } 
      else 
      { 
       ModelState.AddModelError("", "The user name or password provided is incorrect."); 
      } 
     } 

     // If we got this far, something failed, redisplay form 
     return View(model); 
    } 
+0

Я понимаю модель входа в формы и использую ее для обычного веб-сайта. Как это работает для спокойного обслуживания? Как пользователь предоставляет логин? – Nikhil

+0

MVC по-прежнему работает с использованием проверки подлинности форм. При поиске какой-либо системы/службы будет вызываться mvc uri, передавая сетевые учетные данные. Если это так, то подход выше кажется прекрасным. (Но лучше вы можете использовать BaseController и наследовать от него все дочерние контроллеры. Затем вы можете написать тот же код, что и выше, в методе OnActionExecuting, ** Если не весь код вызывается API **) – Manas

+2

Я думаю, что вы закончили игнорировать слова «сервис» и «базовая аутентификация» в заголовке вопроса при ответе. – humblelistener

8

Refactored версия Адриана

public class BasicAuthenticationAttribute : ActionFilterAttribute 
{ 
    private static readonly string AuthorizationHeader = "Authorization"; 
    private static readonly string BasicHeader = "Basic "; 
    private static readonly string Username = "username"; 
    private static readonly string Password = "password"; 
    private static readonly char[] Separator = ":".ToCharArray(); 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     try 
     { 
      if (!Authenticated(filterContext.HttpContext.Request)) 
       filterContext.Result = new HttpUnauthorizedResult(); 

      base.OnActionExecuting(filterContext); 
     } 
     catch 
     { 
      filterContext.Result = new HttpUnauthorizedResult(); 
     } 
    } 

    private bool Authenticated(HttpRequestBase httpRequestBase) 
    { 
     bool authenticated = false; 

     if (String.IsNullOrEmpty(httpRequestBase.Headers[AuthorizationHeader]) == false && 
      httpRequestBase.Headers[AuthorizationHeader].StartsWith(BasicHeader, StringComparison.InvariantCultureIgnoreCase)) 
     { 
      string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(
       httpRequestBase.Headers[AuthorizationHeader].Substring(BasicHeader.Length))).Split(Separator); 

      if (credentials.Length == 2 && credentials[0] == Username && credentials[1] == Password) 
      { 
       authenticated = true; 
      } 
     } 

     return authenticated; 
    } 
} 
+1

+1 для времени и усилий. Очень полезно. Однако если первое условие должно быть, если «не» аутентифицировано, тогда поднимите HttpUnauthorisedResult. – fluent

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