ASP.NET MVC - проверка подлинности HTTP

Возможно ли, чтобы мое приложение запрашивало имя пользователя и пароль, запрашивая его перед визуализацией представления? Как и в twitter API для получения информации о вашей учетной записи:

http://twitter.com/account/verify_credentials.xml

Итак, перед отображением вида || файл, он просит вас вставить вам имя пользователя и пароль, я думаю, что это делается непосредственно на сервере, так как запрос на завиток основан на имени пользователя: password так же, как это:

curl -u user:password http://twitter.com/account/verify_credentials.xml

Как я пытаюсь построить API, следуя той же структуре, я хотел бы знать, как я могу это сделать на ASP.NET MVC С#. Я уже использовал это на рубиновых рельсах, и это довольно просто:

before_filter :authenticate

def authenticate
    authenticate_or_request_with_http_basic do |username, password|
    username == "foo" && password == "bar"
end

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

Заранее спасибо


UPDATE:

Собственно запрашивать страницу, требующую этой аутентификации (т.е. Twitter) Я должен был бы объявить это по его запросу

request.Credentials = new NetworkCredential("username", "password");

И это будет отражать подсказку имени пользователя и пароля.

Итак, это точно то же самое, но с другой стороны, если возможно предоставить информацию в приглашении проверки подлинности по запросу, как я мог бы потребовать эту аутентификацию на вместо запроса?

Поэтому каждый раз кто-то пытается сделать запрос к моему приложению, например:

http://myapplication/clients/verify_credentials

он должен запросить имя пользователя и пароль с приглашением этого сервера поэтому для получения информации о завитке, например, это будет выглядеть как

curl -u user:password http://myapplication/clients/verify_credentials

Ответ 1

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

Я написал ActionFilterAttribte, чтобы узнать, могу ли я получить нужное поведение, если в web.config не установлен модуль проверки подлинности.

public class RequireBasicAuthentication : ActionFilterAttribute {
   public override void OnActionExecuting(ActionExecutingContext filterContext) {
       var req = filterContext.HttpContext.Request;
       if (String.IsNullOrEmpty(req.Headers["Authorization"])) {
           var res = filterContext.HttpContext.Response;
           res.StatusCode = 401;
           res.AddHeader("WWW-Authenticate", "Basic realm=\"Twitter\"");
           res.End();
       }
   }
}

И действие контроллера:

[RequireBasicAuthentication]
public ActionResult Index() {
    var cred = System.Text.ASCIIEncoding.ASCII
            .GetString(Convert.FromBase64String(
            Request.Headers["Authorization"].Substring(6)))
            .Split(':');
    var user = new { Name = cred[0], Pass = cred[1] };
    return Content(String.Format("user:{0}, password:{1}", 
        user.Name, user.Pass));
}

Это действие успешно печатает имя пользователя и пароль, которые я вводил. Но я действительно сомневаюсь, что это лучший способ сделать это. У вас нет выбора, кроме как запросить имя пользователя и пароль таким образом?

Ответ 2

Вы действительно хотите создать службу, а не веб-приложение, основанное на том, что я прочитал. Я угадываю здесь, но я думаю, что вы выбрали ASP.NET MVC, чтобы воспользоваться маршрутизацией и создать URL-адрес так, как хотите? Исправьте меня, если я ошибаюсь.

На мой взгляд, лучший способ решить проблему, которую вы имеете, - создать веб-службы RESTful с WCF, если вы возвращаете данные. Эта статья должна помочь вам начать работу, если вы хотите пройти этот маршрут.

В противном случае вам нужно будет идти дальше в стек для обработки запроса и проверки подлинности. Если это так, я могу помочь с предоставлением дополнительной информации и кода.

Ответ 3

Я изменил ответ çağdaş, чтобы поместить всю логику в свой собственный атрибут ActionFilter.

public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    public string BasicRealm { get; set; }
    protected string Username { get; set; }
    protected string Password { get; set; }

    public BasicAuthenticationAttribute(string username, string password)
    {
        this.Username = username;
        this.Password = password;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"];
        if (!String.IsNullOrEmpty(auth))
        {
            var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
            var user = new { Name = cred[0], Pass = cred[1] };
            if (user.Name == Username && user.Pass == Password) return;
        }
        var res = filterContext.HttpContext.Response;
        res.StatusCode = 401;
        res.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Ryadel"));
        res.End();
    }
}

Его можно использовать для установки под базовой аутентификацией всего контроллера:

[BasicAuthenticationAttribute("your-username", "your-password", 
    BasicRealm = "your-realm")]
public class HomeController : BaseController
{
   ...
}

или конкретный ActionResult:

public class HomeController : BaseController
{
    [BasicAuthenticationAttribute("your-username", "your-password", 
        BasicRealm = "your-realm")]
    public ActionResult Index() 
    {
        ...
    }
}

ПРИМЕЧАНИЕ. Вышеупомянутая реализация требует, чтобы разработчик вручную ввел имя пользователя и пароль в качестве необходимых параметров ActionFilter, но может быть легко расширен, чтобы обеспечить поддержку любого механизма авторизации (MembershipProvider, Identity ASP.NET, пользовательский пользовательская база на внешней СУБД или файл и т.д.), удалив пользовательский конструктор и соответствующим образом изменив IF IF-блок OnActionExecuting.

Вы также можете читать здесь для получения дополнительной информации.

Ответ 4

Вот путь, который сработал у меня. Это небольшая работа, но это сделает IIS и MVC3 более похожими на все другие системы аутентификации Basic Http, такие как Apache...

Шаг 1.

Убедитесь, что для IIS установлена ​​ "Основная проверка подлинности".

(Пример: Панель управления → Программы и функции → Включение и выключение функций Windows)

* Я использую Windows 7 на данный момент и не уверен, что именно путь. [GOOGLE: установка базовой аутентификации в IIS] должна закрыть вас.

Шаг 2.

Убедитесь, что на вашем сайте включена базовая аутентификация. Если вам нужно было установить это на предыдущем шаге, вам нужно убедиться, что вы reset обслуживаете IIS и что все пулы приложений фактически опустились.

Шаг 3.

(Примечание. Я использую MVC3 и считаю, что это должно работать в большинстве моделей, включая ASP.Net, без особых проблем).
В вашем проекте вам нужно будет добавить следующие классы:

public class ServicePrincipal : IPrincipal { // This answers the "What am I allowed to do" question

  // In real life, this guy will contain all your user info
  // and you can put what ever you like and retrieve it 
  // later via the HttpContext, on your application side.
  // Some fun with casting will be required.

  public static IPrincipal Default { 
    get {
      return new ServicePrincipal {
        Identity = new ServiceIdentity {
          AuthenticationType = "Test",
          IsAuthenticated = true,
          Name = "Basic"
        }
      };
    }
  }

  public IIdentity Identity { get; set; } 

  public bool IsInRole(string role) {
    // If you want to use role based authorization
    // e.g. [Authorize(Roles = "CoolPeople")]
    // This is the place to do it and you can do
    // anything from load info from a db or flat file
    // or simple case statement...though that would 
    // be silly.
    return true;
  }
}

public class ServiceIdentity : IIdentity { // This answers the "Who Am I" Question
  public string AuthenticationType { get; set; }

  public bool IsAuthenticated { get; set; }

  public string Name { get; set; }
}


public class ServiceModule : IHttpModule { // This is the module for IIS
  public void Init(HttpApplication context) {
    context.AuthenticateRequest += this.BasicAuthenticationRequest;
  }

  public void BasicAuthenticationRequest(object sender, EventArgs e) {
    HttpApplication app = sender as HttpApplication;

    if( !ServiceProvider.Authenticate(app.Context) ) {
      // Total FAIL!
    }
  }

  public void Dispose() {
    // Clean up the mess, if needed.
  }

}

public class ServiceProvider {

  public static bool Authenticate( HttpContext context ) {
    // For the example we are going to create a nothing user
    // say he is awesome, pass him along through and be done.
    // The heavy lifting of the auth process will go here 
    // in the real world.

    HttpContext.Current.User = ServicePrincipal.Default;
    return true;
  }  
}

Шаг 3a. [Править]

Здесь разные библиотеки, которые вы будете использовать

using System.Security.Principal;
using System.Web;

Просто хотел бросить их. Я ненавижу, когда люди оставляют их.:)

Шаг 4.

Добавьте в свою веб-конфигурацию следующее. Обратите внимание, что я включаю в себя структуру окружения, например тег "Конфигурация"... Это просто дорожная карта, если у вас уже есть тэг конфигурации, не добавляйте другого, или IIS расстраивается с вами.

<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ServiceCredentialModule" type="{Namespace}.ServiceModule"/>
    </modules>
  </system.webServer>
<configuration>

Обратите внимание, что пространство имен в {Namespace}.ServiceModule - это пространство имен, которое вы кладете классы со стадии 3 в.

... и это в значительной степени.