///
/// JWT载荷实体
///
public sealed class JWTPlayloadInfo
{
///
/// jwt签发者
///
public string iss { get; set; } = "Berry.Service";
///
/// jwt所面向的用户
///
public string sub { get; set; } = "ALL";
///
/// 接收jwt的一方
///
public string aud { get; set; } = "guest";
///
/// jwt的签发时间
///
public string iat { get; set; } = DateTimeHelper.GetTimeStamp(DateTime.Now).ToString();
///
/// jwt的过期时间,这个过期时间必须要大于签发时间.默认60分钟
///
public string exp { get; set; }
///
/// 定义在什么时间之前,该jwt都是不可用的.
///
public int nbf { get; set; }
///
/// jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
///
public string jti { get; set; } = CommonHelper.GetGuid();
///
/// 用户ID。自定义字段
///
public string userid { get; set; }
///
/// 扩展字段。自定义字段
///
public string extend { get; set; }
}
JWTHelper.cs:
///
/// JWT操作帮助类
///
public sealed class JWTHelper
{
///
/// 签发Token
///
/// 载荷
///
public static string GetToken(JWTPlayloadInfo playload)
{
string token = String.Empty;
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
//设置过期时间
DateTime time = DateTime.Now.AddMinutes(120);
playload.exp = DateTimeHelper.GetTimeStamp(time).ToString();
Dictionary dict = playload.Object2Dictionary();
//获取私钥
string secret = GetSecret();
//将Token保存在缓存中
if (!string.IsNullOrEmpty(playload.aud) && playload.aud.Equals("guest"))
{
//计算公用Token
token = CacheFactory.GetCacheInstance().GetCache("JWT_TokenCacheKey:Guest", () =>
{
return encoder.Encode(dict, secret);
}, time);
}
else
{
//计算Token
token = CacheFactory.GetCacheInstance().GetCache($"JWT_TokenCacheKey:{playload.aud}", () =>
{
return encoder.Encode(dict, secret);
}, time);
}
return token;
}
///
/// Token校验
///
///
///
public static JWTPlayloadInfo CheckToken(string token)
{
if (string.IsNullOrEmpty(token)) return null;
IJsonSerializer serializer = new JsonNetSerializer();
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);
//获取私钥
string secret = GetSecret();
JWTPlayloadInfo playloadInfo = decoder.DecodeToObject(token, secret, true);
if (playloadInfo != null)
{
if (!string.IsNullOrEmpty(playloadInfo.aud) && playloadInfo.aud.Equals("guest"))
{
string cacheToken = CacheFactory.GetCacheInstance().GetCache("JWT_TokenCacheKey:Guest");
return Check(playloadInfo, cacheToken, token) ? playloadInfo : null;
}
else
{
string cacheToken = CacheFactory.GetCacheInstance().GetCache($"JWT_TokenCacheKey:{playloadInfo.aud}");
return Check(playloadInfo, cacheToken, token) ? playloadInfo : null;
}
}
return null;
}
private static bool Check(JWTPlayloadInfo info, string cacheToken, string token)
{
if (string.IsNullOrEmpty(cacheToken)) return false;
if (string.IsNullOrEmpty(token)) return false;
if (!cacheToken.Equals(token)) return false;
//Token过期
DateTime exp = DateTimeHelper.GetDateTime(info.exp);
if (DateTime.Now > exp)
{
if (!string.IsNullOrEmpty(info.aud) && info.aud.Equals("guest"))
{
CacheFactory.GetCacheInstance().RemoveCache("JWT_TokenCacheKey:Guest");
}
else
{
CacheFactory.GetCacheInstance().RemoveCache($"JWT_TokenCacheKey:{info.aud}");
}
return false;
}
return true;
}
///
/// 获取私钥
///
///
private static string GetSecret()
{
//TODO 从文件中去读真正的私钥
return "eyJpc3MiOiJCZXJyeS5TZXJ2aWNlIiwic3ViIjoiMTgyODQ1OTQ2MTkiLCJhdWQiOiJndWVzdCIsImlhdCI6IjE1MzEzODE5OTgiLCJleHAiOiIxNTMxMzg5MTk4IiwibmJmIjowLCJqdGkiOiI1YzdmN2ZhM2E4ODVlODExYTEzNTQ4ZDIyNGMwMWQwNSIsInVzZXJpZCI6bnVsbCwiZXh0ZW5kIjpudWxsfQ";
}
}
自定义忽略验证特性:
///
/// 忽略验证
///
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class IgnoreTokenAttribute : Attribute
{
public bool Ignore { get; set; }
///
/// 忽略验证.默认忽略
///
///
public IgnoreTokenAttribute(bool ignore = true)
{
this.Ignore = ignore;
}
}
自定义Action拦截器,处理验证逻辑:
public class CustomActionFilterAttribute : ActionFilterAttribute
{
/// 在调用操作方法之前发生。
/// 操作上下文。
public override void OnActionExecuting(HttpActionContext actionContext)
{
string isInterfaceSignature = ConfigHelper.GetValue("IsInterfaceSignature");
if (isInterfaceSignature.ToLower() == "false") return;
BaseJsonResult resultMsg = null;
//授权码
string accessToken = string.Empty;
//操作上下文请求信息
HttpRequestMessage request = actionContext.Request;
//数字签名数据
if (request.Headers.Contains("Authorization"))
{
accessToken = HttpUtility.UrlDecode(request.Headers.GetValues("Authorization").FirstOrDefault());
}
//接受客户端预请求
if (actionContext.Request.Method == HttpMethod.Options)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Accepted);
return;
}
//忽略不需要授权的方法
var attributes = actionContext.ActionDescriptor.GetCustomAttributes();
if (attributes.Count > 0 && attributes[0].Ignore) return;
//判断请求头是否包含以下参数
if (string.IsNullOrEmpty(accessToken))
{
resultMsg = new BaseJsonResult
{
Status = (int)JsonObjectStatus.ParameterError,
Message = JsonObjectStatus.ParameterError.GetEnumDescription()
};
actionContext.Response = resultMsg.ToHttpResponseMessage();
return;
}
//校验Token是否有效
JWTPlayloadInfo playload = JWTHelper.CheckToken(accessToken);
if (playload == null)
{
resultMsg = new BaseJsonResult
{
Status = (int)JsonObjectStatus.TokenInvalid,
Message = JsonObjectStatus.TokenInvalid.GetEnumDescription()
};
actionContext.Response = resultMsg.ToHttpResponseMessage();
return;
}
else
{
//校验当前用户是否能够操作某些特定方法(比如更新用户信息)
if (!attributes[0].Ignore)
{
if (!string.IsNullOrEmpty(playload.aud) && playload.aud.Equals("guest"))
{
resultMsg = new BaseJsonResult
{
Status = (int)JsonObjectStatus.Unauthorized,
Message = JsonObjectStatus.Unauthorized.GetEnumDescription()
};
actionContext.Response = resultMsg.ToHttpResponseMessage();
return;
}
}
}
base.OnActionExecuting(actionContext);
}
}
在WebApiConfig.cs中注册:
config.Filters.Add(new CustomActionFilterAttribute());
新增获取Token控制器,添加获取Token方法:
///
/// 获取授权Token
///
///
///
[HttpPost]
[IgnoreToken(true)]
public HttpResponseMessage GetJWTToken(GetTokenArgEntity arg)
{
BaseJsonResult resultMsg = this.GetBaseJsonResult();
Logger(this.GetType(), "获取授权Token-GetJWTToken", () =>
{
if (!string.IsNullOrEmpty(arg.t))
{
//TODO 根据UserID校验用户是否存在
if (true)
{
JWTPlayloadInfo playload = new JWTPlayloadInfo
{
iss = "Berry.Service",
sub = arg.Account,
aud = arg.UserId
};
string token = JWTHelper.GetToken(playload);
resultMsg = this.GetBaseJsonResult(token, JsonObjectStatus.Success);
}
else
{
resultMsg = this.GetBaseJsonResult(JsonObjectStatus.UserNotExist);
}
}
else
{
resultMsg = this.GetBaseJsonResult(JsonObjectStatus.Fail, ",请求参数有误。");
}
}, e =>
{
resultMsg = this.GetBaseJsonResult(JsonObjectStatus.Exception, ",异常信息:" + e.Message);
});
return resultMsg.ToHttpResponseMessage();
}
获取Token参数实体:
///
/// 获取Token参数
///
public class GetTokenArgEntity : BaseParameterEntity
{
///
/// 用户ID
///
[Required(ErrorMessage = "UserId不能为空")]
public string UserId { get; set; }
///
/// 帐号
///
[Required(ErrorMessage = "Account不能为空")]
public string Account { get; set; }
}