Вопрос по forms-authentication, asp.net-membership, asp.net-mvc, fiddler, asp.net-web-api – Аутентификация веб-API ASP.NET MVC 4 с поставщиком членства

43

У меня есть проект ASP.NET MVC 4 с использованием веб-API. На контроллере я установил класс, требующий авторизации, используя атрибут [Authorize]. Для проверки подлинности я использую поставщика членства ASP.NET, и мой Web.Config настроен на использование «форм». Аутентификация. Вот где я застрял:

Все отлично работает до тех пор, пока я не закончу тестирование API, и я хочу защитить контроллер с помощью атрибута [Authorize], чтобы я мог начать тестирование аутентификации для пользователей в моем поставщике членства. Поэтому я запускаю Fiddler и выполняю тот же вызов, добавляя атрибут Authorization: Basic вместе с именем пользователя: password от моего провайдера членства следующим образом:

enter image description here

Ответ, который я получаю, - 401 не авторизован и находится под «Auth». Я получаю "Нет заголовка WWW-Authenticate." Затем я понимаю, что API ищет ключ в кодировке SHA1. Поэтому я запускаю генератор SHA1 из поиска и получаю хэш для моего имени пользователя: пароль и обновляю свой заголовок запроса следующим образом:

enter image description here

Это тоже не работает, и я получаю те же результаты. Кроме того, мне, очевидно, нужен какой-то «общий секретный ключ». использовать с сервером для декодирования моего имени пользователя / пароля.

Итак, мои вопросы:

How do I get this key from the server (or in this case Virtual IIS running off VS 2012). How do I use this to make Authenticated calls in Fiddler using usernames/passwords from an ASP.NET Membership Provider. How will I use this in my client application to make the same calls (C# WPF App). Is this best practive when combined with SSL on my HTTP calls? If not what is?

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

Ваш Ответ

1   ответ
68

базовая аутентификация с SSL. На стороне сервера мы могли бы написать собственный обработчик делегирования, который проверит учетные данные, запросив зарегистрированного нами поставщика услуг, и, если он действителен, получит роли и установит текущего участника:

public class BasicAuthenticationMessageHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var authHeader = request.Headers.Authorization;

        if (authHeader == null)
        {
            return base.SendAsync(request, cancellationToken);
        }

        if (authHeader.Scheme != "Basic")
        {
            return base.SendAsync(request, cancellationToken);
        }

        var encodedUserPass = authHeader.Parameter.Trim();
        var userPass = Encoding.ASCII.GetString(Convert.FromBase64String(encodedUserPass));
        var parts = userPass.Split(":".ToCharArray());
        var username = parts[0];
        var password = parts[1];

        if (!Membership.ValidateUser(username, password))
        {
            return base.SendAsync(request, cancellationToken);
        }

        var identity = new GenericIdentity(username, "Basic");
        string[] roles = Roles.Provider.GetRolesForUser(username);
        var principal = new GenericPrincipal(identity, roles);
        Thread.CurrentPrincipal = principal;
        if (HttpContext.Current != null)
        {
            HttpContext.Current.User = principal;
        }

        return base.SendAsync(request, cancellationToken);
    }
}

Затем мы регистрируем этот обработчик вApplication_Start:

GlobalConfiguration.Configuration.MessageHandlers.Add(
    new BasicAuthenticationMessageHandler()
);

Теперь у нас может быть контроллер Api, который будет украшен атрибутом [Authorize], чтобы гарантировать, что только аутентифицированные пользователи могут получить доступ к его действиям:

[Authorize]
public class ValuesController : ApiController
{
    public string Get()
    {
        return string.Format("Hello {0}", User.Identity.Name);
    }
}

Хорошо, теперь давайте посмотрим на пример клиента:

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

class Program
{
    static void Main()
    {
        // since for testing purposes I am using IIS Express
        // with an invalid SSL certificate I need to desactivate
        // the check for this certificate.
        ServicePointManager.ServerCertificateValidationCallback += 
            (sender, certificate, chain, sslPolicyErrors) => true;

        using (var client = new HttpClient())
        {
            var buffer = Encoding.ASCII.GetBytes("john:secret");
            var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(buffer));
            client.DefaultRequestHeaders.Authorization = authHeader;
            var task = client.GetAsync("https://localhost:44300/api/values");
            if (task.Result.StatusCode == HttpStatusCode.Unauthorized)
            {
                Console.WriteLine("wrong credentials");
            }
            else
            {
                task.Result.EnsureSuccessStatusCode();
                Console.WriteLine(task.Result.Content.ReadAsAsync<string>().Result);
            }
        }
    }
}
Здравствуйте, метод: & quot; Membership.ValidateUser () & quot; возвращает ложь Я предполагаю, что мне нужно установить соединение с базой данных по умолчанию для членства? Если да, то где мне это сделать?
Спасибо, Дарин, это именно то, что мне было нужно! INNVTV
@ Слаума, я не могу воспроизвести это. Может быть, вы могли бы начать новый поток, объясняя шаг за шагом, как воспроизвести проблему (конечно, начиная с пустого проекта).
Я не мог воспроизвести это сам в новом проекте. Но в то же время я обнаружил, чтоUser принципал правильный в конструкторе ApiController, но неверный в методе контроллера. Между ними находится пользовательский MediaTypeFormatter. Установив некоторые точки останова, я вижу, что цепочка вызовов: ApiController constructor-> MediaTypeFormatter-> ApiController метод. Каким-то образом в форматере основной файл перезаписывается, хотя я не использую ничего, что связано с безопасностью. Если я закомментирую регистрацию форматера в global.asax, принципал останется верным. Мне нужно продолжить отладку ...
User.Identity.Name в контроллере метод для меня пуст,User.Identity.IsAuthenticated являетсяfalse, Я вижу в отладчике, чтоThread.CurrentPrincipal устанавливается на принципала с правильным именем пользователя и ролями в обработчике сообщений. Так же[Authorization(Roles=...)] атрибут соблюдается: если я использую пользователя с неправильными ролями, я получаю несанкционированный ответ и не достигаю метода контроллера. НоUser.Identity не имеет значения, которое я установил в обработчике сообщений. У вас есть идея, что может быть не так?

Похожие вопросы