Отмените JWT, используя C # - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть пользовательский класс Authorize, который я использую для аннулирования токена, когда пользователь запрашивает данные или что-либо с сервера

, но всякий раз, когда токен истекает, принцип все равно возвращает IsAuthenticated как истину и все еще вызываетконтроллеры и получить данные.

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

Обновление 1: генерация токенов

public static string GenerateToken(User user)
{
    int expireMinutes;
    try
    {
        expireMinutes = string.IsNullOrEmpty(ConfigurationManager.AppSettings["SessionTimeInMinutes"])
            ? 30
            : int.Parse(ConfigurationManager.AppSettings["SessionTimeInMinutes"]);
    }
    catch (Exception)
    {
        expireMinutes = 30;
    }
    var symmetricKey = Convert.FromBase64String(Secret);
    var tokenHandler = new JwtSecurityTokenHandler();
    var now = DateTime.Now;
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new[]
        {
            new Claim(ClaimTypes.Email, user.Email)
            ,new Claim(ClaimTypes.Name, user.FirstName + " " + user.LastName)
            ,new Claim("uid", user.Id.ToString())
            ,new Claim("cid", user.ClientId.ToString())
            ,new Claim("rid", string.Join(",", user.Roles.Select(r => r.RoleId).ToList()))
        }),
        Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),
        IssuedAt = now,
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature)
    };
    var stoken = tokenHandler.CreateToken(tokenDescriptor);
    var token = tokenHandler.WriteToken(stoken);
    return token;
}

Авторизационный токен на стороне сервера

 public async Task AuthenticateAsync(
        HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        var excludedList = new List<string>();
        excludedList.Add("/api/Security/IsMustChangePassword");
        excludedList.Add("/api/Security/IsTwoFactorEnabled");

        if (!excludedList.Contains(context.ActionContext.Request.RequestUri.LocalPath))
        {
            var request = context.Request;
            var authorization = request.Headers.Authorization;
            if (authorization == null || authorization.Scheme != "Token")
            {
                return;
            }
            if (string.IsNullOrEmpty(authorization.Parameter))
            {
                context.ErrorResult = new AuthenticationFailureResult("Missing Jwt Token", request);
                return;
            }

            //{
            //    context.ErrorResult = new AuthenticationFailureResult("Invalid token", request);
            //    return;
            //}
            var token = authorization.Parameter;
            var principal = await AuthenticateJwtToken(token).ConfigureAwait(true);
            var userId = int.Parse(new JwtManager().GetUserIdFromToken(token));
            var accountManager = new AccountManager();
            var user = accountManager.GetUserDetails(userId);
            var newToken = JwtManager.GenerateToken(user);

            if (principal == null)
                context.ErrorResult = new AuthenticationFailureResult("Invalid token", request);
            else
                context.Principal = principal;

            if (principal.Identity.IsAuthenticated)
            {
                var expiryDate = JwtManager.GetSecurityToken(token).ValidTo.ToLocalTime();
                if ((DateTime.Now - expiryDate).TotalSeconds > 0)
                {
                    context.Request.Headers.Authorization = null;
                    context.Request.RequestUri = null;


                }
                else
                {
                    var authorize = new AuthenticationHeaderValue("token", newToken);
                    context.Request.Headers.Authorization = authorize;
                    context.ActionContext.Request.Headers.Authorization = authorization;
                }
            }



        }

    }

    private static bool ValidateToken(string token, out string username, out 
    string passwordHash)
    {
        username = null;
        passwordHash = null;
        try
        {
            var principle = JwtManager.GetPrincipal(token);
            var identity = principle.Identity as ClaimsIdentity;

            if (identity == null)
                return false;

            if (!identity.IsAuthenticated)
                return false;

            var usernameClaim = identity.FindFirst(ClaimTypes.Name);
            var passwordClaim = identity.FindFirst(ClaimTypes.Hash);

            username = usernameClaim?.Value;
            passwordHash = passwordClaim?.Value;

            return !string.IsNullOrEmpty(username);

            var user = identity.FindFirst(username);
            return (user != null);
            //return (user != null && user.PasswordHash == passwordHash);
        }
        catch (NullReferenceException)
        {
            return false;
        }
    }

    protected Task<IPrincipal> AuthenticateJwtToken(string token)
    {
        string username;
        string passwordHash;
        if (!ValidateToken(token, out username, out passwordHash))
            return Task.FromResult<IPrincipal>(null);
        // 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) };
        //claims.Add(new Claim(ClaimTypes.Hash, passwordHash));
        // Add more claims if needed: Roles, ...

        var identity = new ClaimsIdentity(claims, "Jwt");
        IPrincipal user = new ClaimsPrincipal(identity);
        return Task.FromResult(user);
    }

    public Task ChallengeAsync(HttpAuthenticationChallengeContext context,
        CancellationToken cancellationToken)
    {
        var authorization = context.Request.Headers.Authorization;
        var excludedList =
            new List<string> {
                "/api/Security/IsMustChangePassword",
                "/api/Security/IsTwoFactorEnabled" };
        if (context.Request.Headers.Authorization != null)
        {
            if (!excludedList.Contains(context.ActionContext.Request.RequestUri.LocalPath))
            {
                var token = context.Request.Headers.Authorization.Parameter;
                var userId = int.Parse(new JwtManager().GetUserIdFromToken(token));
                var accountManager = new AccountManager();
                var user = accountManager.GetUserDetails(userId);
                var newToken = JwtManager.GenerateToken(user);
                var expiryDate = JwtManager.GetSecurityToken(token).ValidTo.ToLocalTime();
                if ((DateTime.Now - expiryDate).TotalSeconds > 0)
                {

                    context.Request.Headers.Authorization = null;
                    context.Request.RequestUri = null;
                    context.Request.RequestUri = new Uri("/Login");
                }
                else
                {
                    var authorize = new AuthenticationHeaderValue("token", newToken);
                    context.Request.Headers.Authorization = authorize;
                    context.ActionContext.Request.Headers.Authorization = authorization;
                }
                Challenge(context);

            }
        }
        else
        {
            var req = context.Request.RequestUri;
            var url = context.Request.RequestUri = new Uri($"http://{req.Host}:{req.Port}/api/Security/login");
            context.Request.RequestUri = url;
            context.Request.Headers.Authorization = null;
            context.Result= new AuthenticationFailureResult(string.Empty, new HttpRequestMessage());
        }


        return Task.FromResult(0);

    }

1 Ответ

0 голосов
/ 11 февраля 2019

Прежде всего: JWT - это просто клиентский токен, которым клиент может манипулировать.Здесь нет абсолютной безопасности.JWT защищен ключом symmetirc, но не может быть аннулирован сам.Действительный токен остается действительным до истечения срока его действия.Это недостаток JWT (как @TimBiegeleisen указал в комментариях), что сам токен не может быть легко признан недействительным.

Если пользователь работает слишком долго и выходит из системы автоматически, срок действия JWT истек и все хорошо.Там нет никаких хлопот, так как он иссякает естественным путем, и вам не нужно действовать.

Чтобы сделать токен недействительным, вам нужно создать новый токен с Expires = now.AddMinutes(-1).Таким образом, при следующей проверке JWT в следующий раз, когда вы увидите, что срок его действия истек.

Случай, когда пользователь может сохранить JWT и использовать его даже после выхода из системы, может быть получен только при внесении в черный список JWT или при ведениикакой-то другой вид серверной сессии дополнительно (который не работает, например, с веб-сервисом без сохранения состояния).

РЕДАКТИРОВАТЬ: Удалена неверная информация и добавлен дополнительный способ аннулировать JWT (черный список)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...