Подтвердить что ты не робот

Аутентификация на основе токена в веб-API без какого-либо пользовательского интерфейса

Я разрабатываю API REST в ASP.Net Web API. Мой API будет доступен только через клиентов, не поддерживающих браузер. Мне нужно реализовать безопасность для моего API, поэтому я решил пойти с аутентификацией на основе токена. У меня есть ясное понимание аутентификации на токенах и прочитал несколько руководств, но у них у всех есть пользовательский интерфейс для входа. Мне не нужен какой-либо пользовательский интерфейс для входа, поскольку данные для входа будут переданы клиентом через HTTP POST, который будет авторизован из нашей базы данных. Как я могу реализовать проверку подлинности на токенах в моем API? Обратите внимание: мой API будет доступен на высокой частоте, поэтому я также должен заботиться о производительности. Пожалуйста, дайте мне знать, если я могу объяснить это лучше.

4b9b3361

Ответ 1

Я думаю, что есть некоторая путаница в различии между MVC и Web Api. Короче говоря, для MVC вы можете использовать форму входа и создать сеанс с использованием файлов cookie. Для Web Api сеанса нет. Вот почему вы хотите использовать токен.

Вам не нужна форма входа. Конечная точка Token - это все, что вам нужно. Как описано в Win, вы отправляете учетные данные в конечную точку маркера, где она обрабатывается.

Здесь некоторый код С# на стороне клиента, чтобы получить токен:

    //using System;
    //using System.Collections.Generic;
    //using System.Net;
    //using System.Net.Http;
    //string token = GetToken("https://localhost:<port>/", userName, password);

    static string GetToken(string url, string userName, string password) {
        var pairs = new List<KeyValuePair<string, string>>
                    {
                        new KeyValuePair<string, string>( "grant_type", "password" ), 
                        new KeyValuePair<string, string>( "username", userName ), 
                        new KeyValuePair<string, string> ( "Password", password )
                    };
        var content = new FormUrlEncodedContent(pairs);
        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
        using (var client = new HttpClient()) {
            var response = client.PostAsync(url + "Token", content).Result;
            return response.Content.ReadAsStringAsync().Result;
        }
    }

Чтобы использовать токен, добавьте его в заголовок запроса:

    //using System;
    //using System.Collections.Generic;
    //using System.Net;
    //using System.Net.Http;
    //var result = CallApi("https://localhost:<port>/something", token);

    static string CallApi(string url, string token) {
        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
        using (var client = new HttpClient()) {
            if (!string.IsNullOrWhiteSpace(token)) {
                var t = JsonConvert.DeserializeObject<Token>(token);

                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Add("Authorization", "Bearer " + t.access_token);
            }
            var response = client.GetAsync(url).Result;
            return response.Content.ReadAsStringAsync().Result;
        }
    }

Где токен:

//using Newtonsoft.Json;

class Token
{
    public string access_token { get; set; }
    public string token_type { get; set; }
    public int expires_in { get; set; }
    public string userName { get; set; }
    [JsonProperty(".issued")]
    public string issued { get; set; }
    [JsonProperty(".expires")]
    public string expires { get; set; }
}

Теперь для серверной части:

В Startup.Auth.cs

        var oAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider("self"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // https
            AllowInsecureHttp = false
        };
        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(oAuthOptions);

И в ApplicationOAuthProvider.cs код, который фактически предоставляет или запрещает доступ:

//using Microsoft.AspNet.Identity.Owin;
//using Microsoft.Owin.Security;
//using Microsoft.Owin.Security.OAuth;
//using System;
//using System.Collections.Generic;
//using System.Security.Claims;
//using System.Threading.Tasks;

public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
    private readonly string _publicClientId;

    public ApplicationOAuthProvider(string publicClientId)
    {
        if (publicClientId == null)
            throw new ArgumentNullException("publicClientId");

        _publicClientId = publicClientId;
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

        var user = await userManager.FindAsync(context.UserName, context.Password);
        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }

        ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager);
        var propertyDictionary = new Dictionary<string, string> { { "userName", user.UserName } };
        var properties = new AuthenticationProperties(propertyDictionary);

        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
        // Token is validated.
        context.Validated(ticket);
    }

    public override Task TokenEndpoint(OAuthTokenEndpointContext context)
    {
        foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
        {
            context.AdditionalResponseParameters.Add(property.Key, property.Value);
        }
        return Task.FromResult<object>(null);
    }

    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        // Resource owner password credentials does not provide a client ID.
        if (context.ClientId == null)
            context.Validated();

        return Task.FromResult<object>(null);
    }

    public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
    {
        if (context.ClientId == _publicClientId)
        {
            var expectedRootUri = new Uri(context.Request.Uri, "/");

            if (expectedRootUri.AbsoluteUri == context.RedirectUri)
                context.Validated();
        }
        return Task.FromResult<object>(null);
    }

}

Как вы можете видеть, нет контроллера, участвующего в извлечении токена. Фактически, вы можете удалить все ссылки MVC, если хотите только Web Api. Я упростил код на стороне сервера, чтобы сделать его более читаемым. Вы можете добавить код для повышения безопасности.

Убедитесь, что вы используете только SSL. Внесите обязательный атрибут RequireHttpsAttribute.

Вы можете использовать атрибуты Authorize/AllowAnonymous для защиты своего веб-Api. Кроме того, вы можете добавлять фильтры (например, RequireHttpsAttribute), чтобы сделать ваш Web Api более безопасным. Надеюсь, это поможет.

Ответ 2

ASP.Net Web API уже имеет встроенный сервер авторизации. Вы можете увидеть его внутри Startup.cs при создании нового веб-приложения ASP.Net с шаблоном веб-API.

OAuthOptions = new OAuthAuthorizationServerOptions
{
    TokenEndpointPath = new PathString("/Token"),
    Provider = new ApplicationOAuthProvider(PublicClientId),
    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
    // In production mode set AllowInsecureHttp = false
    AllowInsecureHttp = true
};

Все, что вам нужно сделать, это опубликовать URL-адрес, закодированное имя пользователя и пароль внутри строки запроса.

/Token/userName=johndoe%40example.com&password=1234&grant_type=password

Если вы хотите узнать больше деталей, вы можете посмотреть Регистрация пользователя и вход в систему - Angular С обратной стороны с веб-интерфейсом Дебора Курата.