TOKEN的使用及在C#中的实现
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
TOKEN的使⽤及在C#中的实现
转⾃:
⾸先说下什么是 JWT -- JSON WEB TOKEN,⽹上关于它的介绍已经很多很多啦,在此,推荐给⼤家⼀篇写的⽐较好的⽂章:
以及Token的组成部分:
OK,今天我想介绍的不再是理论,⽽是如何在C#中应⽤,说⽩了就是怎么写程序呗。
借⽤⽂章中⼀句话:
基于token的鉴权机制类似于http协议也是⽆状态的,它不需要在服务端去保留⽤户的认证信息或者会话信息。
这就意味着基于token认证机制的应⽤不需要去考虑⽤户在哪⼀台服务器登录了,这就为应⽤的扩展提供了便利。
流程上是这样的:
⽤户使⽤⽤户名密码来请求服务器
服务器进⾏验证⽤户的信息
服务器通过验证发送给⽤户⼀个token
客户端存储token,并在每次请求时附送上这个token值
服务端验证token值,并返回数据
这个token必须要在每次请求时传递给服务端,它应该保存在请求头⾥。
OK,按照上述的流程,⾸先我们应当拿到登录的账户,密码等信息,验证通过后,⽣成TOKEN并发送给客户端,之后客户端的每个请求只需带上这个TOKEN,服务器端对这个TOKEN验证,验证通过后即可访问服务器资源,。
具体在C#中如何模仿这个流程呢?
⽤户使⽤⽤户名密码来请求服务器
服务器进⾏验证⽤户的信息
上述⼆个步骤其实是个登录过程,在此不作说明!
服务器通过验证发送给⽤户⼀个token
发送给客户端⼀个Token,这个就需要我们⽣成Token了,那么怎样⽣成呢?理论模块可参考:Token的组成部分:
1、⽤C#⽣成Token:
⾸先引⼊JWT.dll
Token⽣成的具体代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/*----------------------------------------------------------------
Copyright (C) 2017 陈卧龙
⽂件名:monCS
⽂件功能描述:Token相关操作
----------------------------------------------------------------*/
namespace monCS
{
public class CommonToken
{
public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥属于私钥
public static string GenToken(TokenInfo M)
{
var jwtcreated =
Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);
var jwtcreatedOver =
Math.Round((DateTime.UtcNow.AddHours(2) - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);
var payload = new Dictionary<string, dynamic>
{
{"iss", M.iss},//⾮必须。
issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。
{"iat", jwtcreated},//⾮必须。
issued at。
token创建时间,unix时间戳格式
{"exp", jwtcreatedOver},//⾮必须。
expire 指定token的⽣命周期。
unix时间戳格式
{"aud", M.aud},//⾮必须。
接收该JWT的⼀⽅。
{"sub", M.sub},//⾮必须。
该JWT所⾯向的⽤户
{"jti", M.jti},//⾮必须。
JWT ID。
针对当前token的唯⼀标识
{"UserName", erName},//⾃定义字段⽤于存放当前登录⼈账户信息
{"UserPwd", erPwd},//⾃定义字段⽤于存放当前登录⼈登录密码信息
{"UserRole", erRole},//⾃定义字段⽤于存放当前登录⼈登录权限信息
};
return JWT.JsonWebToken.Encode(payload, SecretKey,
JWT.JwtHashAlgorithm.HS256);
}
}
public class TokenInfo
{
public TokenInfo()
{
iss = "签发者信息";
aud = "";
sub = "HomeCare.VIP";
jti = DateTime.Now.ToString("yyyyMMddhhmmss");
UserName = "jack.chen";
UserPwd = "jack123456";
UserRole = "HomeCare.Administrator";
}
//
public string iss { get; set; }
public string aud { get; set; }
public string sub { get; set; }
public string jti { get; set; }
public string UserName { get; set; }
public string UserPwd { get; set; }
public string UserRole { get; set; }
}
}
2、将⽣成的Token发送给客户端后,随后,客户端的每次请求只需带上这个Token即可
⼀般都是将Token存放在Http请求的Headers中,也就是:context.Request.Headers,那么如何接收请求头中的Token呢?接收到Token后如何验证呢?
验证TOKEN时就需要构建 MVC Action 过滤器(AuthorizeAttribute)了,不过在构建 AuthorizeAttribute 之前,有必要对 AuthorizeAttribute 说明下,如下:
⾸先,AuthorizeAttribute 类位于System.Web.Http 命名空间下及System.Web.Mvc命名空间下,
⼀般情况下,如果你需要对C# MVC 控制器的访问作认证与授权,你需要⽤System.Web.Mvc命名空间下的 AuthorizeAttribute ,如果你需要对C# API 控制器的访问作认证与授权,你需要⽤System.Web.Http 命名空间下的 AuthorizeAttribute !
OK,知道了上述两种不同命名空间下的 AuthorizeAttribute ,下⾯以范例作为说明:
2.1、⾃定义MVC ACTION 登录授权验证,(由于本篇博客主讲 Token 的验证与实现,因此,关于MVC 登录验证只做代码说明:)
2.1.1、新建⼀个MVC控制器,命名为BaseController,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
namespace TestForToken.Controllers
{
public class BaseController : Controller
{
#region退出登录
///<summary>
///退出登录
///</summary>
public void ClearLogin()
{
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
"",
DateTime.Now,
DateTime.Now.AddMinutes(-30),
false,
"",
"/"
);
//.ASPXAUTH
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
System.Web.HttpCookie authCookie = new System.Web.HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);
}
#endregion
#region⾃定义过滤器
///<summary>
///⾃定义过滤器
///</summary>
///<param name="filterContext"></param>
protected override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = System.Web.HttpContext.Current.Request.Cookies[cookieName];
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
return;
}
if (authTicket != null && er.Identity.IsAuthenticated)
{
string UserName = ;
base.OnActionExecuting(filterContext);
}
else
{
Content("<script >top.location.href='/Home/Login';</script >", "text/html");
//filterContext.HttpContext.Response.Redirect("/Home/Logins");
}
}
#endregion
#region读取错误信息
///<summary>
///读取错误信息
///</summary>
///<returns></returns>
public string GetError()
{
var errors = ModelState.Values;
foreach (var item in errors)
{
foreach (var item2 in item.Errors)
{
if (!string.IsNullOrEmpty(item2.ErrorMessage))
{
return item2.ErrorMessage;
}
}
}
return"";
}
#endregion
}
}
2.2.2、新建⼀个MVC控制器,命名为HomeController,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestForToken.Models;
namespace TestForToken.Controllers
{
public class HomeController : BaseController
{
public ActionResult Login()
{
ClearLogin();
string HX_userName = CommonMethod.getCookie("HX_userName");
string HX_userPwd = CommonMethod.getCookie("HX_userPwd");
ViewBag.HX_userName = HX_userName;
ViewBag.HX_userPwd = HX_userPwd;
return View();
}
[HttpPost]
public object UserLogin(LoginsModel LoginMol)
{
if (ModelState.IsValid)//是否通过Model验证
{
return LoginMol.LoginAction();
}
else
{
return GetError();
}
}
}
}
2.2.3、新建⼀个登录实体类,命名为:LoginsModel,代码如下:
using System;
using System.Collections.Generic;
using ponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Security;
namespace TestForToken.Models
{
public class LoginsModel
{
private readonly object LOCK = new object();
[Required(ErrorMessage = "请输⼊账户号码/⼿机号")]
[RegularExpression(@"^1[34578][0-9]{9}$", ErrorMessage = "⼿机号格式不正确")]
public string UserName { get; set; }
[Required(ErrorMessage = "请输⼊账户密码")]
[DataType(DataType.Password, ErrorMessage = "密码格式不正确")]
public string UserPwd { get; set; }
public bool remember { get; set; }
public string LoginAction()
{
lock (LOCK)
{
string userRole = string.Empty;
//数据库操作代码
int UserId = 0;
if (UserName == "181********" && UserPwd == "181********")
{
UserId = 1;
userRole = "HomeCare.Administrator";
}
else if (UserName == "189********" && UserPwd == "189********")
{
UserId = 2;
userRole = "HomeCare.Vip";
}
else
{
UserId = 3;
userRole = "er";
}
if (UserId != 0)
{
if (remember)
{
CommonMethod.setCookie("HX_userName", UserName, 7);
CommonMethod.setCookie("HX_userPwd", UserPwd, 7);
}
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
UserName + "_" + UserId,
DateTime.Now,
DateTime.Now.AddMinutes(30),
false,
userRole,
"/"
);
//.ASPXAUTH
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
System.Web.HttpCookie authCookie = new System.Web.HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);
return"HomeCare.Administrator";
}
else
{
return"账户密码不存在";
}
}
}
}
}
2.2.4、修改你的Global.asax⽂件,修改代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Web.Security;
namespace TestForToken
{
// 注意: 有关启⽤ IIS6 或 IIS7 经典模式的说明,
// 请访问 /?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
///<summary>
///登录验证、s授权
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
return;
}
string[] roles = erData.Split(',');
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, roles);
er = principal;//存到er中
}
}
}
2.2.5、公共访问类CommonCS部分代码如下:
using System;
using System.Collections.Generic;
using System.Web;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
using System.Drawing;
namespace TestForToken
{
public class CommonMethod
{
#region cookie操作
///<summary>
/// Cookies赋值
///</summary>
///<param name="strName">主键</param>
///<param name="strValue">键值</param>
///<param name="strDay">有效天数</param>
///<returns></returns>
public static bool setCookieForMIn(string strName, string strValue, int Mintius)
{
try
{
HttpCookie Cookie = new HttpCookie(strName);
//Cookie.Domain = "";//当要跨域名访问的时候,给cookie指定域名即可,格式为 Cookie.Expires = DateTime.Now.AddMinutes(Mintius);
Cookie.Value = strValue;
System.Web.HttpContext.Current.Response.Cookies.Add(Cookie);
return true;
}
catch
{
return false;
}
}
///<summary>
/// Cookies赋值
///</summary>
///<param name="strName">主键</param>
///<param name="strValue">键值</param>
///<param name="strDay">有效天数</param>
///<returns></returns>
public static bool setCookie(string strName, string strValue, int strDay)
{
try
{
HttpCookie Cookie = new HttpCookie(strName);
//Cookie.Domain = "";//当要跨域名访问的时候,给cookie指定域名即可,格式为 Cookie.Expires = DateTime.Now.AddDays(strDay);
Cookie.Value = strValue;
System.Web.HttpContext.Current.Response.Cookies.Add(Cookie);
return true;
}
catch
{
return false;
}
}
///<summary>
///读取Cookies
///</summary>
///<param name="strName">主键</param>
///<returns></returns>
public static string getCookie(string strName)
{
HttpCookie Cookie = System.Web.HttpContext.Current.Request.Cookies[strName];
if (Cookie != null)
{
return Cookie.Value.ToString();
}
else
{
return null;
}
}
///<summary>
///删除Cookies
///</summary>
///<param name="strName">主键</param>
///<returns></returns>
public static bool delCookie(string strName)
{
try
{
HttpCookie Cookie = new HttpCookie(strName);
//Cookie.Domain = "";//当要跨域名访问的时候,给cookie指定域名即可,格式为
Cookie.Expires = DateTime.Now.AddDays(-1);
System.Web.HttpContext.Current.Response.Cookies.Add(Cookie);
return true;
}
catch
{
return false;
}
}
#endregion
}
}
2.2.6、公共Token⽣成类代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/*----------------------------------------------------------------
Copyright (C) 2017 陈卧龙
⽂件名:monCS
⽂件功能描述:Token相关操作
----------------------------------------------------------------*/
namespace monCS
{
public class CommonToken
{
public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥属于私钥
public static string GenToken(TokenInfo M)
{
var jwtcreated =
Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);
var jwtcreatedOver =
Math.Round((DateTime.UtcNow.AddHours(2) - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);
var payload = new Dictionary<string, dynamic>
{
{"iss", M.iss},//⾮必须。
issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。
{"iat", jwtcreated},//⾮必须。
issued at。
token创建时间,unix时间戳格式
{"exp", jwtcreatedOver},//⾮必须。
expire 指定token的⽣命周期。
unix时间戳格式
{"aud", M.aud},//⾮必须。
接收该JWT的⼀⽅。
{"sub", M.sub},//⾮必须。
该JWT所⾯向的⽤户
{"jti", M.jti},//⾮必须。
JWT ID。
针对当前token的唯⼀标识
{"UserName", erName},//⾃定义字段⽤于存放当前登录⼈账户信息
{"UserPwd", erPwd},//⾃定义字段⽤于存放当前登录⼈登录密码信息
{"UserRole", erRole},//⾃定义字段⽤于存放当前登录⼈登录权限信息
};
return JWT.JsonWebToken.Encode(payload, SecretKey,
JWT.JwtHashAlgorithm.HS256);
}
}
public class TokenInfo
{
public TokenInfo()
{
iss = "签发者信息";
aud = "";
sub = "HomeCare.VIP";
jti = DateTime.Now.ToString("yyyyMMddhhmmss");
UserName = "jack.chen";
UserPwd = "jack123456";
UserRole = "HomeCare.Administrator";
}
//
public string iss { get; set; }
public string aud { get; set; }
public string sub { get; set; }
public string jti { get; set; }
public string UserName { get; set; }
public string UserPwd { get; set; }
public string UserRole { get; set; }
}
}
2.2.7、新建⼀个登录页⾯,Login.cshtml代码如下:
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<title>账户登录</title>
<link href="~/Content/css/materialize.min.css" rel="stylesheet"/>
<style type="text/css">
html,
body {
height: 100%;
}
html {
display: table;
margin: auto;
}
body {
display: table-cell;
vertical-align: middle;
color:#47c1a8;
}
.margin {
margin: 0 !important;
}
.card-panel{ min-width:350px;}
</style>
<!--[if IE]>
<script src="/libs/html5shiv/3.7/html5shiv.min.js"></script>
<![endif]-->
</head>
<body class="red">
<div id="login-page" class="row">
<div class="col s12 z-depth-6 card-panel">
<form class="login-form">
<div class="row">
<div class="input-field col s12 center">
<img src="/content/images/100.png" alt="" class="responsive-img valign profile-image-login">
<p class="center login-form-text">账户登录</p>
</div>
</div>
<div class="row margin">
<div class="input-field col s12">
<i class="mdi-social-person-outline prefix"></i>
<input class="validate" id="UserName" name="UserName" type="tel" value="@ViewBag.HX_userName">
<label for="tel" data-error="wrong" data-success="right" class="center-align">⼿机号码:</label>
</div>
</div>
<div class="row margin">
<div class="input-field col s12">
<i class="mdi-action-lock-outline prefix"></i>
<input id="UserPwd" name="UserPwd" type="password" value="@ViewBag.HX_userPwd">
<label for="password">密码:</label>
</div>
</div>
<div class="row">
<div class="input-field col s12 m12 l12 login-text">
<input type="checkbox" id="remember-me" name="remember-me"/>
<label for="remember-me">记住我</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<a href="JavaScript:void(0)" class="btn waves-effect waves-light col s12" onclick="Login()">登 录</a>
</div>
</div>
<div class="row">
<div class="input-field col s6 m6 l6">
<p class="margin medium-small"></p>
</div>
<div class="input-field col s6 m6 l6">
<p class="margin right-align medium-small"><a href="/home/forgotpassword">忘记密码?</a></p>
</div>
</div>
</form>
</div>
</div>
<script src="~/Scripts/js/jquery-2.1.0.js"></script>
<script src="~/Scripts/js/materialize.min.js"></script>
<script type="text/javascript">
function Login() {
var UserName = $("#UserName").val();
var UserPwd = $("#UserPwd").val();
var remember = document.getElementById("remember-me").checked;
$(document).ready(function (data) {
$.ajax({
url: "/Home/UserLogin",
type: "post",
contentType: "application/json",
dataType: "text",
data: JSON.stringify({ UserName: UserName, UserPwd: UserPwd, remember: remember }),
success: function (result, status) {
if (result == "HomeCare.Administrator") {
//登录成功跳转
location.href = "/Manger/Index";//管理员登录
}
else {
alert(result);
}
},
error: function (error) {
alert(error);
}
});
});
}
</script>
<!--materialize js-->
</body>
</html>
2.2.8、新建⼀个登录验证属性,继承⾃:System.Web.Mvc.AuthorizeAttribute,代码如下:(千呼万唤始出来啊......~_~)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Mvc;
using System.Web.Security;
namespace TestForToken.Auth2._0
{
public class MvcActionAuth : AuthorizeAttribute
{
public string[] AuthorizeRoleAry = new string[] { "er", "HomeCare.Vip", "HomeCare.Administrator" };//本系统允许的⾓⾊普通⽤户会员超级管理员///<summary>
///⾃定义 MVC 控制前访问权限验证
///</summary>
///<param name="filterContext"></param>
public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
string Role = string.Empty;
string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
string actionName = filterContext.ActionDescriptor.ActionName;
//数据库验证当前Controller及Action允许访问的权限
//简单模拟读取数据库
if (controllerName == "Manger" && actionName == "Index")
{
//得到允许访问 Manger/Index 的权限值
Role = "HomeCare.Administrator,HomeCare.Vip";
}
//
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = System.Web.HttpContext.Current.Request.Cookies[cookieName];
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
return;
}
string[] roles = erData.Split(',');
string NowRole = string.Empty;
foreach (var item in roles)
{
NowRole += item;
}
if (!Role.Contains(NowRole)) //没有权限访问当前控制器 ACtion
{
System.Web.HttpContext.Current.Response.Redirect("/Home/Login");
}
base.OnAuthorization(filterContext);
}
}
}
2.2.9、新建⼀个MVC 控制器,命名为:MangerController,代码如下:
上述代码就不做演⽰了,⼤致过程是这样的:
Manger/Index的访问权限如下:
登录⽤户:
上述截图已经很清晰了,不再作重复说明。
OK,上述代码便是整个MVC 控制器登录验证/授权认证的全部代码。
下⾯我们请出本⽂终极BOSS,如果接收并解析验证接收的TOKEN。
3、下⾯介绍webAPI Controller 的认证授权
3.1、⾸先,我们⾃定义⼀个继承⾃System.Web.Http 命名空间下的AuthorizeAttribute 属性来解析并验证TOKEN
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using .Http;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using monCS;
namespace TestForToken.Auth2._0
{
public class ApiActionAuth : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext context)
{
var authHeader = context.Request.Headers.FirstOrDefault(a => a.Key == "ApiAuthorization");//获取接收的Token
if (context.Request.Headers == null || !context.Request.Headers.Any() || authHeader.Key == null || string.IsNullOrEmpty(authHeader.Value.FirstOrDefault()))
{
Throw401Exception(context, "NoToken");
return;
}
var sendToken = authHeader.Value.FirstOrDefault();
//url获取token
var now = Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);//当前的时间戳var dictPayload = DecodeToken(sendToken);
if (dictPayload == null)
{
Throw401Exception(context, "InvalidToken");
}
double iat = dictPayload["iat"];
double exp = dictPayload["exp"];
//检查令牌的有效期
if (!(iat < now && now < exp))//如果当前时间戳不再Token声明周期范围内,则返回Token过期
{
Throw401Exception(context, "TokenTimeout");
}
//获取Token的⾃定义键值对
int UserId = dictPayload["UserId"];
string UserName = dictPayload["UserName"];
string UserPwd = dictPayload["UserPwd"];
string UserRole = dictPayload["UserRole"];
//把toke⽤户数据放到 er ⾥
ClientUserData clientUserData = new ClientUserData()
{
UserId = UserId,
UserName = UserName,
UserPwd = UserPwd,
UserRole = UserRole
};
if (HttpContext.Current != null)
{
er = new UserPrincipal(clientUserData);
}
}
private static IDictionary<string, dynamic> DecodeToken(string token)
{
try
{
var dictPayload = JWT.JsonWebToken.DecodeToObject(token, CommonToken.SecretKey) as IDictionary<string, dynamic>;
return dictPayload;
}
catch (Exception ex)
{
return null;
}
}
private static void Throw401Exception(HttpActionContext actionContext, string exceptionString)
{
var response = HttpContext.Current.Response;
throw new HttpResponseException(
actionContext.Request.CreateErrorResponse(.HttpStatusCode.Unauthorized, exceptionString ?? "Unauthorized"));
}
private static string RequestToString(HttpRequestMessage request)
{
var message = new StringBuilder();
if (request.Method != null)
message.Append(request.Method);
if (request.RequestUri != null)
message.Append("").Append(request.RequestUri);
return message.ToString();
}
}
}
3.2、新增⼀个存储解析Token结果的类,命名为SysHelper.cs,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Web;
namespace TestForToken.Auth2._0
{
public class SysHelper
{
public static UserPrincipal CurrentPrincipal
{
get
{
return er as UserPrincipal;
}
}
}
public class UserPrincipal : ClientUserData, IPrincipal
{
public IIdentity Identity { get; private set; }
public string[] Roles { get; set; }
public UserPrincipal(ClientUserData clientUserData)
{
this.Identity = new GenericIdentity(string.Format("{0}", erId));
erId = erId;
erName = erName;
erPwd = erPwd;
erRole = erRole;
}
public bool IsInRole(string role)
{
if (Roles.Any(r => r == role))
{
return true;
}
else
{
return false;
}
}
}
public class ClientUserData
{
public int UserId { get; set; }
public string UserName { get; set; }
public string UserPwd { get; set; }
public string UserRole { get; set; }
}
}
3.3、公共Token⽣成⽅法修改如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/*----------------------------------------------------------------
Copyright (C) 2017 陈卧龙
⽂件名:monCS
⽂件功能描述:Token相关操作
----------------------------------------------------------------*/
namespace monCS
{
public class CommonToken
{
public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥属于私钥
public static string GetToken(TokenInfo M)
{
var jwtcreated =
Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);
var jwtcreatedOver =
Math.Round((DateTime.UtcNow.AddHours(2) - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);//TOKEN声明周期⼆⼩时var payload = new Dictionary<string, dynamic>
{
{"iss", M.iss},//⾮必须。
issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。
{"iat", jwtcreated},//⾮必须。
issued at。
token创建时间,unix时间戳格式
{"exp", jwtcreatedOver},//⾮必须。
expire 指定token的⽣命周期。
unix时间戳格式
{"aud", M.aud},//⾮必须。
接收该JWT的⼀⽅。
{"sub", M.sub},//⾮必须。
该JWT所⾯向的⽤户
{"jti", M.jti},//⾮必须。
JWT ID。
针对当前token的唯⼀标识
{"UserId", erId},//⾃定义字段⽤于存放当前登录⼈账户信息
{"UserName", erName},//⾃定义字段⽤于存放当前登录⼈账户信息
{"UserPwd", erPwd},//⾃定义字段⽤于存放当前登录⼈登录密码信息
{"UserRole", erRole},//⾃定义字段⽤于存放当前登录⼈登录权限信息
};
return JWT.JsonWebToken.Encode(payload, SecretKey,
JWT.JwtHashAlgorithm.HS256);
}
}
public class TokenInfo
{
public TokenInfo()
{
iss = "签发者信息";
aud = "";
sub = "HomeCare.VIP";
jti = DateTime.Now.ToString("yyyyMMddhhmmss");
UserId = 1;
UserName = "jack.chen";
UserPwd = "jack123456";
UserRole = "HomeCare.Administrator";
}
//
public string iss { get; set; }
public string aud { get; set; }
public string sub { get; set; }
public string jti { get; set; }
public int UserId { get; set; }
public string UserName { get; set; }
public string UserPwd { get; set; }
public string UserRole { get; set; }
}
}
3.4、定义⼀个MVC API Controller 代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using ;
using .Http;
using System.Web.Http;
using TestForToken.Auth2._0;
namespace TestForToken.Controllers
{
public class MangerApiController : ApiController
{
[ApiActionAuth]
[HttpGet]
public string GetStr()
{
int UserId = erId;
string UserName = erName;
string UserPwd = erPwd;
string UserRole = erRole;
return"当前登录的第三⽅⽤户信息如下,UserId:" + UserId + ",UserName:" + UserName + ",UserPwd:" + UserPwd + ",UserRole:" + UserRole;
}
}
}
OK,有了上述代码我们就可以模拟TOKEN验证了,模拟步骤如下:/
3.5、模拟TOKEN验证:
3.5.1、⽣成TOKEN,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using monCS;
namespace TestForToken
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(CommonToken.GetToken(new TokenInfo()));
}
}
}
⽣成的TOKEN为:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiLnrb7lj5HogIXkv6Hmga8iLCJpYXQiOjE1MDk2OTEyODQsImV4cCI6MTUwOTY5ODQ4NCwiYXVkIjoiaHR0cDovL2V4YW1wbGUuY29tIiwic3Vi 3.5.2、将获取的TOKEN(有效期两个⼩时)返回⾄客户端,客户端将获取的TOKEN放在请求头 Headers 中,模拟请求如下(PostMan):
OK,将上述TOKEN随便去掉⼀个字母,请求结果如下:
过期的TOKEN,请求如下:
OK,关于TOKEN更详细的验证,还需要⼤家⾃⾏完善,本篇博客我仅仅只验证了TOKEN是否正确,没有作进⼀步的验证,⼤家可根据项⽬需求,主动完善TOKEN验证代码。
例如:读取TOKEN存放的⽤户名,密码,⾓⾊等信息再作数据库验证。
或者如同上述的MVC 控制器控制,验证⾓⾊等信息,总之,,,,,,,不写了,太累,还有任务没完
成呢。
哈!见谅!
项⽬源码位置:。