对于我的应用程序,我使用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添加cookie:
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上调用方法时,他们会收到未经授权的错误,即使当我删除cookie时,问题仍然存在。我在PC和手机上有问题。
我设置Cookie的方式好吗?