[转载]Json Web Token(jwt)
一种不错的身份验证及授权方案,与 Session 相反,Jwt 将用户信息存放在 Token 的 payload 字段保存在客户端,通过 RSA 加密的方式,保证数据不会被篡改,验证数据有效性。
详细请参考jwt.io。
本文在转载文上做了一些修改,避免初学者走弯路,以下文章中有介绍设置过期时间,还有,token仔细看会发现每次请求到的新token字符串会有细微变化,而不是一成不变的。
1. 开发环境如下
vs2017+ASP.NET MVC 5+.NET FrameWork4.5
2. 在nuget上先添加封装了jwt使用的框架
因为环境是.NET FrameWork4.5 所以我采用3.0.0版本 注意版本问题
3.封装一个JWT帮助类
创建实体类 UserInfo
public string UserName { get; set; }
public string Pwd { get; set; }
public class JwtHelp
{
//私钥 web.config中配置
//"GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
private static string secret = ConfigurationManager.AppSettings["Secret"].ToString();
///
/// 生成JwtToken
///
/// 不敏感的用户数据
///
public static string SetJwtEncode(Dictionary payload)
{
//格式如下
//var payload = new Dictionary
//{
// { "username","admin" },
// { "pwd", "claim2-value" }
//};
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(payload, secret);
return token;
}
///
/// 根据jwtToken 获取实体
///
/// jwtToken
///
public static UserInfo GetJwtDecode(string token)
{
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);
var userInfo = decoder.DecodeToObject(token, secret, verify: true);//token为之前生成的字符串
return userInfo;
}
public class UserInfo
{
public string username{ get; set; }
public string pwd{ get; set; }
}
public class tokenResult
{
public string Token { get; set; }
public bool Success { get; set; }
public string Message { get; set; }
}
}
}
4.创建JwtController 生成jwtToken看看效果
Get 请求需要改成这样
return Json(result,JsonRequestBehavior.AllowGet);
public class JwtController : Controller
{
// GET: Jwt
public ActionResult Index()
{
return View();
}
///
/// 创建jwtToken
///
///
///
///
public ActionResult CreateToken(string username, string pwd)
{
tokenResult result = new tokenResult();
//假设用户名为"admin",密码为"123"
if (username == "admin" && pwd == "123")
{
IDateTimeProvider provider = new UtcDateTimeProvider();
var now = provider.GetNow();
var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds);
var payload = new Dictionary
{
{ "username",username },
{ "pwd", pwd },
{ "exp", secondsSinceEpoch + 60*30} //失效时间 秒 30分钟
};
result.Token = JwtHelp.SetJwtEncode(payload);
result.Success = true;
result.Message = "成功";
}
else
{
result.Token = "";
result.Success = false;
result.Message = "生成token失败";
}
return Json(result);
//get请求需要修改成这样
//return Json(result,JsonRequestBehavior.AllowGet);
}
}
5.我喜欢postMan测试神器 你值得拥有
6.AuthorizeAttribute
接下来,我们需要编写有关权限控制及token解析有关的代码。
所有操作都在Home里面 将受限Action或Controller打上标签, 所有访问都想先权限验证通过后才能访问
编写一个继承AuthorizeAttribute实现类,根据实体类是否相等。
我先简单描述下程序执行过程
1.进入验证入口->验证核心代码->
1.返回false进入验证处理失败
2.返回true进入访问的controller/action里面
public class MyAuthorizeAttribute : AuthorizeAttribute
{
///
/// 验证入口
///
///
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
}
///
/// 验证核心代码
///
///
///
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//前端请求api时会将token存放在名为"auth"的请求头中
var authHeader = httpContext.Request.Headers["auth"];
if (authHeader == null)
{
httpContext.Response.StatusCode = 403;
return false;
}
var userinfo = JwtHelp.GetJwtDecode(authHeader);
//举个例子 生成jwtToken 存入redis中
//这个地方用jwtToken当作key 获取实体val 然后看看jwtToken根据redis是否一样
if (userinfo.UserName == "admin" && userinfo.Pwd == "123")
return true;
httpContext.Response.StatusCode = 403;
return false;
}
///
/// 验证失败处理
///
///
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
base.HandleUnauthorizedRequest(filterContext);
if (filterContext.HttpContext.Response.StatusCode == 403)
{
filterContext.Result = new RedirectResult("/Error");
filterContext.HttpContext.Response.Redirect("/Home/Error");
}
}
}