十年河东,十年河西,莫欺少年穷。

学无止境,精益求精。

做个宣传,资源已上传CSDN,评价好不错,如下:

等等吧,总之反馈还可以!

突然发现整个十月份自己还没有写一篇博客......哎,说出来都是泪啊,最近加班实在实在实在是太多了,真的没有多余的时间写博客。这不,今天也在加班中...索性,利用加班的一些时间写篇博客吧!

首先说下什么是 JWT -- JSON WEB TOKEN,网上关于它的介绍已经很多很多啦,在此,推荐给大家一篇写的比较好的文章:什么是 JWT -- JSON WEB TOKEN

以及Token的组成部分Token存放的信息

OK,今天我想介绍的不再是理论,而是如何在C#中应用,说白了就是怎么写程序呗。

借用 什么是 JWT -- JSON WEB TOKEN 文章中一句话:

基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

流程上是这样的:

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息
  • 服务器通过验证发送给用户一个token
  • 客户端存储token,并在每次请求时附送上这个token值
  • 服务端验证token值,并返回数据

这个token必须要在每次请求时传递给服务端,它应该保存在请求头里。

OK,按照上述的流程,首先我们应当拿到登录的账户,密码等信息,验证通过后,生成TOKEN并发送给客户端,之后客户端的每个请求只需带上这个TOKEN,服务器端对这个TOKEN验证,验证通过后即可访问服务器资源,。

具体在C#中如何模仿这个流程呢?

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息

上述二个步骤其实是个登录过程,在此不作说明!

  • 服务器通过验证发送给用户一个token

发送给客户端一个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 陈卧龙 文件名:TestForToken.CommonCS
文件功能描述:Token相关操作
----------------------------------------------------------------*/
namespace TestForToken.CommonCS
{
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(, , , , , , DateTimeKind.Utc)).TotalSeconds + );
var jwtcreatedOver =
Math.Round((DateTime.UtcNow.AddHours() - new DateTime(, , , , , , DateTimeKind.Utc)).TotalSeconds + );
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", M.UserName},//自定义字段 用于存放当前登录人账户信息
{"UserPwd", M.UserPwd},//自定义字段 用于存放当前登录人登录密码信息
{"UserRole", M.UserRole},//自定义字段 用于存放当前登录人登录权限信息
};
return JWT.JsonWebToken.Encode(payload, SecretKey,
JWT.JwtHashAlgorithm.HS256);
}
} public class TokenInfo
{
public TokenInfo()
{
iss = "签发者信息";
aud = "http://example.com";
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(
,
"",
DateTime.Now,
DateTime.Now.AddMinutes(-),
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 && filterContext.HttpContext.User.Identity.IsAuthenticated)
{
string UserName = authTicket.Name; 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 System.ComponentModel.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 = ;
if (UserName == "" && UserPwd == "")
{
UserId = ;
userRole = "HomeCare.Administrator";
}
else if (UserName == "" && UserPwd == "")
{
UserId = ;
userRole = "HomeCare.Vip";
}
else
{
UserId = ;
userRole = "HomeCare.User";
}
if (UserId != )
{
if (remember)
{
CommonMethod.setCookie("HX_userName", UserName, );
CommonMethod.setCookie("HX_userPwd", UserPwd, );
}
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
,
UserName + "_" + UserId,
DateTime.Now,
DateTime.Now.AddMinutes(),
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 经典模式的说明,
// 请访问 http://go.microsoft.com/?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 = authTicket.UserData.Split(',');
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, roles);
Context.User = principal;//存到HttpContext.User中    
}
}
}

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 = ".xxx.com";//当要跨域名访问的时候,给cookie指定域名即可,格式为.xxx.com
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 = ".xxx.com";//当要跨域名访问的时候,给cookie指定域名即可,格式为.xxx.com
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 = ".xxx.com";//当要跨域名访问的时候,给cookie指定域名即可,格式为.xxx.com
Cookie.Expires = DateTime.Now.AddDays(-);
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 陈卧龙 文件名:TestForToken.CommonCS
文件功能描述:Token相关操作
----------------------------------------------------------------*/
namespace TestForToken.CommonCS
{
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(, , , , , , DateTimeKind.Utc)).TotalSeconds + );
var jwtcreatedOver =
Math.Round((DateTime.UtcNow.AddHours() - new DateTime(, , , , , , DateTimeKind.Utc)).TotalSeconds + );
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", M.UserName},//自定义字段 用于存放当前登录人账户信息
{"UserPwd", M.UserPwd},//自定义字段 用于存放当前登录人登录密码信息
{"UserRole", M.UserRole},//自定义字段 用于存放当前登录人登录权限信息
};
return JWT.JsonWebToken.Encode(payload, SecretKey,
JWT.JwtHashAlgorithm.HS256);
}
} public class TokenInfo
{
public TokenInfo()
{
iss = "签发者信息";
aud = "http://example.com";
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="http://apps.bdimg.com/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[] { "HomeCare.User", "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 = authTicket.UserData.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 System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using TestForToken.CommonCS; 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(, , , , , , DateTimeKind.Utc)).TotalSeconds + );//当前的时间戳
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用户数据放到 HttpContext.Current.User 里
ClientUserData clientUserData = new ClientUserData()
{
UserId = UserId,
UserName = UserName,
UserPwd = UserPwd,
UserRole = UserRole };
if (HttpContext.Current != null)
{
HttpContext.Current.User = 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(System.Net.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 HttpContext.Current.User 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}", clientUserData.UserId));
this.UserId = clientUserData.UserId;
this.UserName = clientUserData.UserName;
this.UserPwd = clientUserData.UserPwd;
this.UserRole = clientUserData.UserRole;
} 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 陈卧龙 文件名:TestForToken.CommonCS
文件功能描述:Token相关操作
----------------------------------------------------------------*/
namespace TestForToken.CommonCS
{
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(, , , , , , DateTimeKind.Utc)).TotalSeconds + );
var jwtcreatedOver =
Math.Round((DateTime.UtcNow.AddHours() - new DateTime(, , , , , , DateTimeKind.Utc)).TotalSeconds + );//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", M.UserId},//自定义字段 用于存放当前登录人账户信息
{"UserName", M.UserName},//自定义字段 用于存放当前登录人账户信息
{"UserPwd", M.UserPwd},//自定义字段 用于存放当前登录人登录密码信息
{"UserRole", M.UserRole},//自定义字段 用于存放当前登录人登录权限信息
};
return JWT.JsonWebToken.Encode(payload, SecretKey,
JWT.JwtHashAlgorithm.HS256);
}
} public class TokenInfo
{
public TokenInfo()
{
iss = "签发者信息";
aud = "http://example.com";
sub = "HomeCare.VIP";
jti = DateTime.Now.ToString("yyyyMMddhhmmss");
UserId = ;
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 System.Net;
using System.Net.Http;
using System.Web.Http;
using TestForToken.Auth2._0; namespace TestForToken.Controllers
{
public class MangerApiController : ApiController
{
[ApiActionAuth]
[HttpGet]
public string GetStr()
{
int UserId = SysHelper.CurrentPrincipal.UserId;
string UserName = SysHelper.CurrentPrincipal.UserName;
string UserPwd = SysHelper.CurrentPrincipal.UserPwd;
string UserRole = SysHelper.CurrentPrincipal.UserRole;
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 TestForToken.CommonCS; 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.eyJpc3MiOiLnrb7lj5HogIXkv6Hmga8iLCJpYXQiOjE1MDk2OTEyODQsImV4cCI6MTUwOTY5ODQ4NCwiYXVkIjoiaHR0cDovL2V4YW1wbGUuY29tIiwic3ViIjoiSG9tZUNhcmUuVklQIiwianRpIjoiMjAxNzExMDMwMjQxMTkiLCJVc2VySWQiOjEsIlVzZXJOYW1lIjoiamFjay5jaGVuIiwiVXNlclB3ZCI6ImphY2sxMjM0NTYiLCJVc2VyUm9sZSI6IkhvbWVDYXJlLkFkbWluaXN0cmF0b3IifQ.IryLo19SSghi34LD1PNIOmzgzavQrnmGBD42pdojXtg

3.5.2、将获取的TOKEN(有效期两个小时)返回至客户端,客户端将获取的TOKEN放在 请求头 Headers 中,模拟请求如下(PostMan):

OK,将上述TOKEN随便去掉一个字母,请求结果如下:

过期的TOKEN,请求如下:

OK,关于TOKEN更详细的验证,还需要大家自行完善,本篇博客我仅仅只验证了TOKEN是否正确,没有作进一步的验证,大家可根据项目需求,主动完善TOKEN验证代码。

例如:读取TOKEN存放的用户名,密码,角色等信息再作数据库验证。或者如同上述的MVC 控制器控制,验证角色等信息,总之,,,,,,,不写了,太累,还有任务没完成呢。

哈!见谅!

项目源码位置http://download.csdn.net/download/wolongbb/10102574

希望大家喜欢....

@陈卧龙的博客

JSON WEB TOKEN,简单谈谈TOKEN的使用及在C#中的实现的更多相关文章

  1. [转载]JSON WEB TOKEN,简单谈谈TOKEN的使用及在C#中的实现

    https://www.cnblogs.com/chenwolong/p/Token.html

  2. JSON Web Tokens简单学习

    JWT用于加密生成安全认证的令牌,存储登录验证成功的部分用户信息 一.安装JWT 二.加密 解密 代码 /*存储在加密字符串的信息*/ var payload = new Dictionary< ...

  3. 你知道你对 JSON Web Token 的认识存在误解吗

    1.前言 JSON Web Token (JWT) 其实目前已经广为软件开发者所熟知了,但是 JOSE (Javascript Object Signing and Encryption) 却鲜有人知 ...

  4. 一分钟简单了解 JSON Web Token

    JSON Web Token(JWT)是一个开放的标准(RFC 7519),它定义了一个紧凑且自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息.由于此信息是经过数字签名的,因此可以被验证 ...

  5. JWT(JSON Web Token) Java与.Net简单编码实现

    参考 JWT(JSON WEB TOKENS)-一种无状态的认证机制 基于Token的WEB后台认证机制 各种语言版本的基于HMAC-SHA256的base64加密 Java与.Net实现实现 // ...

  6. JSON Web Token 是什么?

    免费获得官方JWT手册并深入学习JWT吧! 简介 JSON Web Token(缩写JWT),是一套开放的标准(RFC 7519),它定义了一种紧凑且自URL安全的方式,以JSON对象的方式在各方之间 ...

  7. 使用Json Web Token设计Passport系统

    >>Token Auth机制 基于Token的身份验证是无状态的,我们不将用户信息存在服务器或Session中. 相比原始的Cookie+Session方式,更适合分布式系统的用户认证,绕 ...

  8. [认证授权] 2.OAuth2(续) & JSON Web Token

    0. RFC6749还有哪些可以完善的? 0.1. 撤销Token 在上篇[认证授权] 1.OAuth2授权中介绍到了OAuth2可以帮我们解决第三方Client访问受保护资源的问题,但是只提供了如何 ...

  9. Hacking JWT(JSON Web Token)

    0x01 JWT工作流程 JSON Web Token(JWT)是一个非常轻巧的规范. 这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息. JWT常被用于前后端分离,可以和Restful ...

随机推荐

  1. Linux 操作系统主机名变成bogon怎么解决?

    主机名变成bogon怎么解决? by:授客 QQ:1033553122   一:使用hostname命令 [laiyu@localhost ~]$ hostname localhost.localdo ...

  2. python txt文件数据转excel

    txt content: perf.txt 2018-11-12 16:48:58 time: 16:48:58 load average: 0.62, 0.54, 0.56 mosquitto CP ...

  3. 什么是DDoS攻击?DDoS防御的11种方针详解

    对于遭受DDOS攻击的情况是让人很尴尬的,如果我们有良好的DDoS防御方法,那么很多问题就将迎刃而解,我们来看看我们有哪些常用的有效地方法来做好DDoS防御呢. 对于DDoS防御的理解: 对付DDOS ...

  4. 阿里云 centos7 django + uWSGI+Nginx + python3 部署攻略

    centos7+nginx+python3+django+uwsgi配置Django 项目部署   1.租的服务器(选择centos)的话,需要在阿里云后台控制台开放几个端口,克隆一下已开放的端口,t ...

  5. python第四十三天--第三模块考核

    面向对象: 概念:类,实例化,对象,实例 属性: 公有属性:在类中定义 成员属性:在方法中定义 私有属性:在方法中使用 __属性  定义 限制外部访问 方法: 普通方法 类方法: @classmeth ...

  6. CSS网页菜单

    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserContro ...

  7. 常用css字体英文写法

    font-family: 'Microsoft Yahei',sans-serif; 宋体:SimSun 黑体:SimHei

  8. 深度理解select、poll和epoll

    在linux 没有实现epoll事件驱动机制之前,我们一般选择用select或者poll等IO多路复用的方法来实现并发服务程序.在大数据.高并发.集群等一些名词唱得火热之年代,select和poll的 ...

  9. iTween for Unity

    你曾经在你的游戏中制作过动画吗?问这个问题可能是愚蠢的,几乎每个Game都有动画,虽然有一些没有,但你必须处理有动画和没有动画.让我们结识 ITween. iTween 官方网站:http://itw ...

  10. CentOS7下用firewall-cmd控制端口与端口转发

    1.firewalld 守护进程 2.控制端口/服务 3.伪装IP 4.端口转发 实现目标:服务器A和服务器B都是内网互通的,但是只有服务器A是有外网然后现在做端口转发实现服务器B能使用服务器A的外网 ...