Аутентификация JWT с Asp.Net Web Api не работает - PullRequest
0 голосов
/ 14 ноября 2018

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

Мои два класса для этого:

internal class JwtAuthenticationAttribute : AuthorizeAttribute
{

    private const string CookieName = "jwt";

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        base.OnAuthorization(actionContext);
    }
    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
        base.HandleUnauthorizedRequest(actionContext);
    }

    public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        return base.OnAuthorizationAsync(actionContext, cancellationToken);
    }

    protected override bool IsAuthorized(HttpActionContext httpContext)
    {
        var authToken = HttpContext.Current.Request.Cookies[CookieName];

        if (authToken == null)
        {
            return false;
        }

        var jwtValue = authToken.Value;
        var isValid = JwtManager.ValidateToken(jwtValue, HttpContext.Current.Request.UserHostName, HttpContext.Current.Request.UserAgent, out var userId, out var expireAt);
        if (!isValid) return false;

        isValid = HasRole(userId);
        //var ts = expireAt.Subtract(DateTime.UtcNow);
        //var limitTs = new TimeSpan(0, 0, 30, 0);
        //if (ts.TotalMilliseconds < 0)
        //{
         //   return false;
        //}
       /* else if (ts.TotalMilliseconds > 0 && ts < limitTs)
        {
            var token = JwtManager.GenerateToken(userId);
            var response = HttpContext.Current.Response;
            response.Cookies.Add(new HttpCookie(CookieName, token));
            var host = System.Web.HttpContext.Current.Request.UserHostAddress;
            var agent = System.Web.HttpContext.Current.Request.UserAgent;
            var service = new ServiceToken();
            service.Add(new Token(token, userId, host, agent));
        }*/
        return isValid;
    }

    private bool HasRole(Guid userId)
    {
        var serviceUser = new ServiceUser();
        var userRoles = serviceUser.GetRoles(userId).Select(x => x.Label).ToList();
        var res = true;
        var requiredRoles = Roles.Split(',');

        if (String.IsNullOrWhiteSpace(Roles) || requiredRoles.Length <= 0)
            return true;

        res = false;
        foreach (var role in requiredRoles)
        {
            if (userRoles.Contains(role))
            {
                res = true;
            }
        }

        return res;
    }

    protected Task<IPrincipal> AuthenticateJwtToken(string token)
    {
        var request = HttpContext.Current.Request;
        if (!JwtManager.ValidateToken(token, request.UserHostName, request.UserAgent, out var userId,
            out _)) return Task.FromResult<IPrincipal>(null);

        var claims = new List<Claim>
        {
            new Claim("Id", userId.ToString()),
        };

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

        return Task.FromResult(user);
    }
}

и второй класс:

public class JwtManager
{
    public const string Secret = ""; // your symmetric

    public static string GenerateToken(Guid userId, 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("Id", userId.ToString())
            }),
            Expires = DateTime.MaxValue,
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature)
        };

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

        return token;
    }

    public static ClaimsPrincipal GetPrincipal(string token, out DateTime expireAt)
    {
        expireAt = DateTime.MinValue;
        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 = false,
                ValidateIssuer = false,
                ValidateAudience = false,
                IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
            };

            SecurityToken securityToken;
            var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
            expireAt = securityToken.ValidTo;
            return principal;
        }

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

    public static bool ValidateToken(string token, string host, string agent, out Guid userId, out DateTime expireAt)
    {
        userId = Guid.Empty;
        var simplePrinciple = JwtManager.GetPrincipal(token, out expireAt);
        if (simplePrinciple == null)
            return false;

        var identity = simplePrinciple.Identity as ClaimsIdentity;

        if (identity == null)
            return false;

        if (!identity.IsAuthenticated)
            return false;

        var idClaim = identity.FindFirst("Id");
        if (idClaim?.Value != null) userId = Guid.Parse(idClaim?.Value);

        if (userId == Guid.Empty)
            return false;

        // More validate to check whether username exists in system
        var serviceToken = new ServiceToken();
        return serviceToken.Exists(x => x.Value == token );
    }      
}

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

и вот код, как я добавляю свои куки с моим jtw:

    private string SetTokenForUser(Guid username)
    {
        string token = JwtManager.GenerateToken(username);
        string host = HttpContext.Current.Request.UserHostAddress;
        string agent = HttpContext.Current.Request.UserAgent;
        HttpContext.Current.Response.Cookies.Add(new HttpCookie(CookieName, token));
        var tokeNewn = new Token(token, username, host, agent);
        _serviceToken.Add(tokeNewn);
        return tokeNewn.Value;
    }

Моя проблема в том, что иногда у некоторых пользователей, когда они входят в систему и вызывают метод на jwtcontroller, они получают Несанкционированную ошибку, даже когда я удаляю куки, проблема остается. У меня проблема на ПК и мобильном телефоне.

Хороший ли у меня способ установить куки?

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