Проверка подлинности JWT для веб Asp.Net API-интерфейс



Я пытаюсь поддерживать JWT bearer token (JSON Web Token) в моем приложении Web api, и я теряюсь.



Я вижу поддержку .net core и OWIN приложения.

В настоящее время я размещаю свое приложение над IIS.



как я могу достичь этого модуля аутентификации в моем приложении? Есть ли способ я могу использовать <authentication> конфигурация аналогична тому, как я использую формуWindows authentication?

1051   3  

3 ответов:

я ответил на этот вопрос: как обеспечить безопасность веб-API ASP.NET 4 года назад с помощью HMAC.

теперь многое изменилось в безопасности, esp JWT становится популярным. Здесь я попытаюсь объяснить, как использовать JWT самым простым и основным способом, который я могу, чтобы мы не заблудились из джунглей OWIN, Oauth2, ASP.NET личность... :).

если вы не знаете токен JWT, вам нужно немного взглянуть в:

https://tools.ietf.org/html/rfc7519

в основном, токен JWT выглядит так:

<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>

пример:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXvcj9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmjmijoxndc3nty1nzi0lcjlehaioje0nzc1njy5mjqsimlhdci6mtq3nzu2ntcynh0.6MzD1VwA5AcOcajkFyKhLYybr3h13iZjdyhm9zysdfq

токен JWT имеет три секции:

  1. заголовок: формат JSON, который является закодированных в base64
  2. претензии: формат JSON, который кодируется как base64.
  3. подпись: создается и подписывается на основе заголовка и утверждений, которые кодируются как base64.

если вы используете веб-сайт jwt.io с токеном выше, вы можете декодировать и увидеть токен, как показано ниже:

enter image description here

технически, JWT использует подпись, которая подписывается из заголовков и утверждений с алгоритмом безопасности указывается в заголовках (пример: HMACSHA256). Поэтому JWT необходимо передавать по протоколу HTTPs, если вы храните конфиденциальную информацию в утверждениях.

теперь, чтобы использовать аутентификацию JWT, вам действительно не нужно промежуточное программное обеспечение OWIN, если у вас есть устаревшая система Web Api. Простая концепция заключается в том, как предоставить токен JWT и как проверить токен, когда приходит запрос. Вот и все.

вернуться к демо, чтобы сохранить токен JWT легкий, я только храню username и expiration time в JWT. Но таким образом, вы должны заново построить новый локальный идентификатор (Принципал), чтобы добавить дополнительную информацию, такую как: роли.. если вы хотите сделать авторизацию роли. Но, если вы хотите добавить больше информации в JWT, это зависит от вас, очень гибкий.

вместо использования промежуточного программного обеспечения OWIN вы можете просто предоставить конечную точку токена JWT с помощью действия от контроллера:

public class TokenController : ApiController
{
    // This is naive endpoint for demo, it should use Basic authentication to provide token or POST request
    [AllowAnonymous]
    public string Get(string username, string password)
    {
        if (CheckUser(username, password))
        {
            return JwtManager.GenerateToken(username);
        }

        throw new HttpResponseException(HttpStatusCode.Unauthorized);
    }

    public bool CheckUser(string username, string password)
    {
        // should check in the database
        return true;
    }
}

это наивное действие, в производстве вы должны использовать POST request или обычную конечную точку аутентификации, чтобы обеспечить токенов JWT.

как создать токен на основе username?

вы можете использовать пакет NuGet под названием System.IdentityModel.Tokens.Jwt из MS для создания токена или даже другого пакета, если хотите. В демо, я использую HMACSHA256 С SymmetricKey:

    /// <summary>
    /// Use the below code to generate symmetric Secret Key
    ///     var hmac = new HMACSHA256();
    ///     var key = Convert.ToBase64String(hmac.Key);
    /// </summary>
    private const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";

    public static string GenerateToken(string username, int expireMinutes = 20)
    {
        var symmetricKey = Convert.FromBase64String(Secret);
        var tokenHandler = new JwtSecurityTokenHandler();

        var now = DateTime.UtcNow;
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[]
                    {
                        new Claim(ClaimTypes.Name, username)
                    }),

            Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),

            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature)
        };

        var stoken = tokenHandler.CreateToken(tokenDescriptor);
        var token = tokenHandler.WriteToken(stoken);

        return token;
    }

конечная точка для предоставления токена JWT выполнена, теперь, как проверить JWT, когда приходит запрос, в демо, которое я построил JwtAuthenticationAttribute, который наследует от IAuthenticationFilter, более подробно о фильтре аутентификации в здесь.

С помощью этого атрибута вы можете аутентифицировать любое действие, вы просто помещаете этот атрибут в это действие.

public class ValueController : ApiController
{
    [JwtAuthentication]
    public string Get()
    {
        return "value";
    }
}

вы также можете использовать OWIN middleware или DelegateHander, если вы хотите проверить все входящие запросы для вашего WebApi (не определенного на контроллере или действии)

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

    private static bool ValidateToken(string token, out string username)
    {
        username = null;

        var simplePrinciple = JwtManager.GetPrincipal(token);
        var identity = simplePrinciple.Identity as ClaimsIdentity;

        if (identity == null)
            return false;

        if (!identity.IsAuthenticated)
            return false;

        var usernameClaim = identity.FindFirst(ClaimTypes.Name);
        username = usernameClaim?.Value;

        if (string.IsNullOrEmpty(username))
            return false;

        // More validate to check whether username exists in system

        return true;
    }

    protected Task<IPrincipal> AuthenticateJwtToken(string token)
    {
        string username;

        if (ValidateToken(token, out username))
        {
            // based on username to get more information from database in order to build local identity
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, username)
                // Add more claims if needed: Roles, ...
            };

            var identity = new ClaimsIdentity(claims, "Jwt");
            IPrincipal user = new ClaimsPrincipal(identity);

            return Task.FromResult(user);
        }

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

рабочего процесса, используя библиотеку проверки подлинности (выше пакет NuGet) для проверки вышлю токен, а затем вернуться обратно ClaimsPrincipal. Вы можете выполнить дополнительную проверку, например проверить, существует ли пользователь в вашей системе, и добавить другие пользовательские проверки, если хотите. Код для проверки токена JWT и возврата участника:

   public static ClaimsPrincipal GetPrincipal(string token)
    {
        try
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;

            if (jwtToken == null)
                return null;

            var symmetricKey = Convert.FromBase64String(Secret);

            var validationParameters = new TokenValidationParameters()
            {
               RequireExpirationTime = true,
               ValidateIssuer = false,
               ValidateAudience = false,
               IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
            };

            SecurityToken securityToken;
            var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);

            return principal;
        }

        catch (Exception)
        {
            //should write log
            return null;
        }
    }

если маркер JWT проверен и принципал возвращается, вы должны создать новый локальный идентификатор и поместить в него дополнительную информацию для проверки авторизации роли.

не забудьте добавить config.Filters.Add(new AuthorizeAttribute()); (разрешение по умолчанию) в глобальной области для того, чтобы предотвратите любой анонимный запрос к вашим ресурсам.

вы можете использовать Postman для тестирования демо:

токен запроса (наивный, как я уже упоминал выше, только для демо):

GET http://localhost:{port}/api/token?username=cuong&password=1

поместите токен JWT в заголовок для авторизованного запроса, например:

GET http://localhost:{port}/api/value

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1MjU4LCJleHAiOjE0Nzc1NjY0NTgsImlhdCI6MTQ3NzU2NTI1OH0.dSwwufd4-gztkLpttZsZ1255oEzpWCJkayR_4yvNL1s

демо помещается здесь:https://github.com/cuongle/WebApi.Jwt

Я думаю, что вы должны использовать некоторые 3D-участника Server для поддержки проверки подлинности маркеров и нет из коробки поддержка проверки подлинности в веб-API 2.

однако есть проект OWIN для поддержки некоторого формата подписанного токена (не JWT). Он работает как сокращенный протокол OAuth, чтобы обеспечить простую форму аутентификации для веб-сайта.

вы можете прочитать больше об этом, например здесь.

Это довольно долго, но большинство деталей детали с контроллерами и ASP.NET личность, которая вам может вообще не понадобиться. Наиболее важными являются

Шаг 9: добавьте поддержку генерации токенов носителя OAuth

Шаг 12: тестирование внутреннего API

там вы можете прочитать, как настроить конечную точку (например, "/token"), к которой вы можете получить доступ из интерфейса (и подробную информацию о формате запроса).

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

Я также реализовать Jason Web Token API в моем проекте, вы можете скачать по этой ссылке JWT API Token. Вы можете использовать [authorize] чтобы проверить, аутентифицирован ли пользователь или нет?

Comments

    Ничего не найдено.