看JWT,可以先看下网站jwt.io,这个网站可以解密你的token,解密后可以看到,一个JWT的token是由3部分构成:
1)Header(头),解密后格式:
{
"typ": "JWT",
"alg": "HS256"
}2)PayLoad,需要注意的是,PayLoad解密后是明文存在的,比如:
{
"exp": 1536310394,
"logininfo": {
"UserId": "00000000-0000-0000-0000-000000000000",
"UserName": "admin"
}
}exp是什么时候过期,Unix时间戳。logininfo是放到里面的一个JSON实体。
3) 第三部分为签名。
在webapi中,我们先Nuget搜索JWT,然后使用下面代码生成token:
var adminLogin = new AdminLoginInfo() {
UserId = Guid.Empty,
UserName = "admin"
};
string key = "ahuinan";
var payload = new Dictionary<string, object>
{
{ "exp", DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds() },
{ "logininfo",JsonConvert.SerializeObject(adminLogin)}
};
//采用HS256加密算法
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
string token = encoder.Encode(payload, key);接下来可以在webapi中添加一个过滤器验证token的有效性,
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext filterContext)
{
var attr = filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
bool isAnonymous = attr.Any(p => p is AllowAnonymousAttribute);
if (isAnonymous) { return; }
var authHeader = from h in filterContext.Request.Headers where h.Key == "Authorization" select h.Value.FirstOrDefault();
bool successLogin = false;
string errMsg = "";
if (authHeader != null)
{
//对token进行解密
try
{
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);
var token = authHeader.FirstOrDefault().Replace("Bearer", "").Trim();
decoder.Decode(token, "ahuinan", verify: true);
successLogin = true;
}
catch (Exception ex)
{
}
}
if (!successLogin)
{
Result r = new Result();
r.ErrorMessage = "请重新登录";
r.ResultCode = ResultCode.Error;
filterContext.Response = filterContext.Request.CreateResponse<Result>(HttpStatusCode.OK, r, "application/json");
return;
}
}当然,我们还需要在Controller层拿到用户名信息等呢,继续封装一下,根据token登陆的ID和用户名,代码如下:
public static T Get<T>(string token,string tokenKey,string jsonKey)
{
try
{
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);
string json = decoder.Decode(token, tokenKey, verify: true);
var dic = decoder.DecodeToObject<Dictionary<string, object>>(token);
return JsonConvert.DeserializeObject<T>(dic[jsonKey].ToString());
}
catch (TokenExpiredException ex)
{
throw new BaseException("请重新登陆,token已失效");
}
catch (SignatureVerificationException ex)
{
throw new BaseException("请重新登陆,签名错误");
}
}那么过滤器中的完整代码就变成了:
var attr = filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
bool isAnonymous = attr.Any(p => p is AllowAnonymousAttribute);
if (isAnonymous) { return; }
var authHeader = from h in filterContext.Request.Headers where h.Key == "Authorization" select h.Value.FirstOrDefault();
Result r = new Result();
bool successLogin = false;
string errMsg = "";
if (authHeader != null)
{
try
{
var logininfo = TokenHelper.Get<LoginInfo>(authHeader.FirstOrDefault().Replace("Bearer", "").Trim(),
SysGlobalCodeConst.TokenKey,
SysGlobalCodeConst.LoginInfoKey);
if (logininfo != null)
{
filterContext.ControllerContext.RouteData.Values[SysGlobalCodeConst.LoginInfoKey] = logininfo;
}
successLogin = true;
}
catch (Exception ex)
{
r.ErrorMessage = ex.Message;
}
}
else {
r.ErrorMessage = "请重新登录";
}
if (!successLogin)
{
r.ResultCode = ResultCode.Error;
filterContext.Response = filterContext.Request.CreateResponse<Result>(HttpStatusCode.OK, r, "application/json");
return;
}
}Controller层取登陆信息的代码如下:
/// <summary>
/// 取得登陆信息
/// </summary>
protected LoginInfo CurrentUser
{
get
{
return this.RequestContext.RouteData.Values[SysGlobalCodeConst.LoginInfoKey] as LoginInfo;
}
}