2023年6月20日发(作者:)

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:⾸先引⼊en⽣成的具体代码如下:using System;using c;using ;using ;/*---------------------------------------------------------------- Copyright (C) 2017 陈卧龙

⽂件名:CS ⽂件功能描述:Token相关操作----------------------------------------------------------------*/namespace CS{ public class CommonToken { public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥 属于私钥 public static string GenToken(TokenInfo M) { var jwtcreated = (( - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var jwtcreatedOver = ((rs(2) - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var payload = new Dictionary { {"iss", },//⾮必须。issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。 {"iat", jwtcreated},//⾮必须。issued at。 token创建时间,unix时间戳格式 {"exp", jwtcreatedOver},//⾮必须。expire 指定token的⽣命周期。unix时间戳格式 {"aud", },//⾮必须。接收该JWT的⼀⽅。 {"sub", },//⾮必须。该JWT所⾯向的⽤户 {"jti", },//⾮必须。JWT ID。针对当前token的唯⼀标识 {"UserName", me},//⾃定义字段 ⽤于存放当前登录⼈账户信息 {"UserPwd", d},//⾃定义字段 ⽤于存放当前登录⼈登录密码信息 {"UserRole", le},//⾃定义字段 ⽤于存放当前登录⼈登录权限信息 }; return (payload, SecretKey, 256); } } public class TokenInfo { public TokenInfo() { iss = "签发者信息"; aud = ""; sub = ""; jti = ng("yyyyMMddhhmmss"); UserName = ""; UserPwd = "jack123456"; UserRole = "strator"; } // 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中,也就是:s,那么如何接收请求头中的Token呢?接收到Token后如何验证呢?验证TOKEN时就需要构建 MVC Action 过滤器(AuthorizeAttribute)了,不过在构建 AuthorizeAttribute 之前,有必要对 AuthorizeAttribute 说明下,如下:⾸先,AuthorizeAttribute 类位于 命名空间下及命名空间下,⼀般情况下,如果你需要对C# MVC 控制器的访问作认证与授权,你需要⽤命名空间下的 AuthorizeAttribute ,如果你需要对C# API 控制器的访问作认证与授权,你需要⽤ 命名空间下的 AuthorizeAttribute !OK,知道了上述两种不同命名空间下的 AuthorizeAttribute ,下⾯以范例作为说明:2.1、⾃定义MVC ACTION 登录授权验证,(由于本篇博客主讲 Token 的验证与实现,因此,关于MVC 登录验证只做代码说明:)2.1.1、新建⼀个MVC控制器,命名为BaseController,代码如下:using System;using c;using ;using ;using ;using ty;namespace llers{ public class BaseController : Controller { #region 退出登录 ///

/// 退出登录 /// public void ClearLogin() { FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, "", , utes(-30), false, "", "/" ); //.ASPXAUTH string encryptedTicket = t(authTicket); okie authCookie = new okie(ookieName, encryptedTicket); (authCookie); } #endregion #region ⾃定义过滤器 /// /// ⾃定义过滤器 /// /// protected override void OnActionExecuting(ExecutingContext filterContext) { string cookieName = ookieName; HttpCookie authCookie = s[cookieName]; FormsAuthenticationTicket authTicket = null; try { authTicket = t(); } catch (Exception ex) { return; } if (authTicket != null && enticated) { string UserName = ;

onExecuting(filterContext); } else { Content("", "text/html"); //ct("/Home/Logins"); } } #endregion #region 读取错误信息 ///

/// 读取错误信息 /// /// public string GetError() { var errors = ; foreach (var item in errors) { foreach (var item2 in ) { if (!OrEmpty(essage)) { return essage; } } } return ""; } #endregion }}2.2.2、新建⼀个MVC控制器,命名为HomeController,代码如下:using System;using c;using ;using ;using ;using ;namespace llers{ public class HomeController : BaseController { public ActionResult Login() { ClearLogin(); string HX_userName = kie("HX_userName"); string HX_userPwd = kie("HX_userPwd"); _userName = HX_userName; _userPwd = HX_userPwd; return View(); } [HttpPost] public object UserLogin(LoginsModel LoginMol) { if (d)//是否通过Model验证 { return ction(); } else { return GetError(); } } }}2.2.3、新建⼀个登录实体类,命名为:LoginsModel,代码如下:using System;using c;using notations;using ;using ;using ty;namespace { 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(rd, ErrorMessage = "密码格式不正确")] public string UserPwd { get; set; } public bool remember { get; set; } public string LoginAction() { lock (LOCK) { string userRole = ; //数据库操作代码 int UserId = 0; if (UserName == "" && UserPwd == "") { UserId = 1; userRole = "strator"; } else if (UserName == "" && UserPwd == "") { UserId = 2; userRole = ""; } else { UserId = 3; userRole = ""; } if (UserId != 0) { if (remember) { kie("HX_userName", UserName, 7); kie("HX_userPwd", UserPwd, 7); } FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, UserName + "_" + UserId, , utes(30), false, userRole, "/" ); //.ASPXAUTH string encryptedTicket = t(authTicket); okie authCookie = new okie(ookieName, encryptedTicket); (authCookie); return "strator"; } else { return "账户密码不存在"; } } } }}2.2.4、修改你的⽂件,修改代码如下:using System;using c;using ;using pal;using ;using ;using ;using zation;using g;using ty;namespace TestForToken{ // 注意: 有关启⽤ IIS6 或 IIS7 经典模式的说明, // 请访问 /?LinkId=9394801 public class MvcApplication : plication { protected void Application_Start() { erAllAreas(); er(uration); erGlobalFilters(s); erRoutes(); erBundles(s); } /// /// 登录验证、s授权 /// /// /// protected void Application_AuthenticateRequest(Object sender, EventArgs e) { string cookieName = ookieName; HttpCookie authCookie = s[cookieName]; FormsAuthenticationTicket authTicket = null; try { authTicket = t(); } catch (Exception ex) { return; } string[] roles = (','); FormsIdentity id = new FormsIdentity(authTicket); GenericPrincipal principal = new GenericPrincipal(id, roles); = principal;//存到中    

} }}2.2.5、公共访问类CommonCS部分代码如下:using System;using c;using ;using tions;using ;using rExpressions;using ;using g;namespace TestForToken{ public class CommonMethod { #region cookie操作 ///

/// Cookies赋值 /// /// 主键 /// 键值 /// 有效天数 /// public static bool setCookieForMIn(string strName, string strValue, int Mintius) { try { HttpCookie Cookie = new HttpCookie(strName); // = ".";//当要跨域名访问的时候,给cookie指定域名即可,格式为. s = utes(Mintius); = strValue; (Cookie); return true; } catch { return false; } } /// /// Cookies赋值 /// /// 主键 /// 键值 /// 有效天数 /// public static bool setCookie(string strName, string strValue, int strDay) { try { HttpCookie Cookie = new HttpCookie(strName); // = ".";//当要跨域名访问的时候,给cookie指定域名即可,格式为. s = s(strDay); = strValue; (Cookie); return true; } catch { return false; } } /// /// 读取Cookies /// /// 主键 /// public static string getCookie(string strName) { HttpCookie Cookie = s[strName]; if (Cookie != null) { return ng(); } else { return null; } } /// /// 删除Cookies /// /// 主键 /// public static bool delCookie(string strName) { try { HttpCookie Cookie = new HttpCookie(strName); // = ".";//当要跨域名访问的时候,给cookie指定域名即可,格式为. s = s(-1); (Cookie); return true; } catch { return false; } } #endregion }}2.2.6、公共Token⽣成类代码如下:using System;using c;using ;using ;/*---------------------------------------------------------------- Copyright (C) 2017 陈卧龙

⽂件名:CS ⽂件功能描述:Token相关操作----------------------------------------------------------------*/namespace CS{ public class CommonToken { public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥 属于私钥 public static string GenToken(TokenInfo M) { var jwtcreated = (( - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var jwtcreatedOver = ((rs(2) - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var payload = new Dictionary { {"iss", },//⾮必须。issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。 {"iat", jwtcreated},//⾮必须。issued at。 token创建时间,unix时间戳格式 {"exp", jwtcreatedOver},//⾮必须。expire 指定token的⽣命周期。unix时间戳格式 {"aud", },//⾮必须。接收该JWT的⼀⽅。 {"sub", },//⾮必须。该JWT所⾯向的⽤户 {"jti", },//⾮必须。JWT ID。针对当前token的唯⼀标识 {"UserName", me},//⾃定义字段 ⽤于存放当前登录⼈账户信息 {"UserPwd", d},//⾃定义字段 ⽤于存放当前登录⼈登录密码信息 {"UserRole", le},//⾃定义字段 ⽤于存放当前登录⼈登录权限信息 }; return (payload, SecretKey, 256); } } public class TokenInfo { public TokenInfo() { iss = "签发者信息"; aud = ""; sub = ""; jti = ng("yyyyMMddhhmmss"); UserName = ""; UserPwd = "jack123456"; UserRole = "strator"; } // 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、新建⼀个登录页⾯,代码如下:@{ Layout = null;}

账户登录

2.2.8、新建⼀个登录验证属性,继承⾃:izeAttribute,代码如下:(千呼万唤始出来啊......~_~)using System;using c;using ;using pal;using ;using llers;using ;using ty;namespace 2._0{ public class MvcActionAuth : AuthorizeAttribute { public string[] AuthorizeRoleAry = new string[] { "", "", "strator" };//本系统允许的⾓⾊ 普通⽤户 会员 超级管理员 ///

/// ⾃定义 MVC 控制前访问权限验证 /// /// public override void OnAuthorization(izationContext filterContext) { string Role = ; string controllerName = llerName; string actionName = Name; //数据库验证当前Controller及Action允许访问的权限 //简单模拟 读取数据库 if (controllerName == "Manger" && actionName == "Index") { //得到允许访问 Manger/Index 的权限值 Role = "strator,"; } // string cookieName = ookieName; HttpCookie authCookie = s[cookieName]; FormsAuthenticationTicket authTicket = null; try { authTicket = t(); } catch (Exception ex) { return; } string[] roles = (','); string NowRole = ; foreach (var item in roles) { NowRole += item; } if (!ns(NowRole)) //没有权限访问当前控制器 ACtion { ct("/Home/Login"); }

orization(filterContext); } }}2.2.9、新建⼀个MVC 控制器 ,命名为:MangerController,代码如下:

上述代码就不做演⽰了,⼤致过程是这样的:Manger/Index的访问权限如下:

登录⽤户:

上述截图已经很清晰了,不再作重复说明。OK,上述代码便是整个MVC 控制器 登录验证/授权认证的全部代码。下⾯我们请出本⽂终极BOSS,如果接收并解析验证接收的TOKEN。 3、下⾯介绍webAPI Controller 的认证授权3.1、⾸先,我们⾃定义⼀个继承⾃ 命名空间下的AuthorizeAttribute 属性来解析并验证TOKEN代码如下:using System;using c;using ;using ;using ;using ;using ;using llers;using CS;namespace 2._0{ public class ApiActionAuth : AuthorizeAttribute { public override void OnAuthorization(HttpActionContext context) { var authHeader = rDefault(a => == "ApiAuthorization");//获取接收的Token if (s == null || !() || == null || OrEmpty(rDefault())) { Throw401Exception(context, "NoToken"); return; }

var sendToken = rDefault(); //url获取token

var now = (( - new DateTime(1970, 1, 1, 0, 0, 0, )).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⽤户数据放到 ⾥ ClientUserData clientUserData = new ClientUserData() { UserId = UserId, UserName = UserName, UserPwd = UserPwd, UserRole = UserRole }; if (t != null) { = new UserPrincipal(clientUserData); } } private static IDictionary DecodeToken(string token) { try { var dictPayload = ToObject(token, Key) as IDictionary; return dictPayload; } catch (Exception ex) { return null; } } private static void Throw401Exception(HttpActionContext actionContext, string exceptionString) { var response = se; throw new HttpResponseException( ErrorResponse(orized, exceptionString ?? "Unauthorized")); } private static string RequestToString(HttpRequestMessage request) { var message = new StringBuilder(); if ( != null) (); if (tUri != null) (" ").Append(tUri); return ng(); } }}3.2、新增⼀个存储解析Token结果的类,命名为,代码如下:using System;using c;using ;using pal;using ;namespace 2._0{ public class SysHelper { public static UserPrincipal CurrentPrincipal { get { return as UserPrincipal; } } } public class UserPrincipal : ClientUserData, IPrincipal { public IIdentity Identity { get; private set; } public string[] Roles { get; set; } public UserPrincipal(ClientUserData clientUserData) { ty = new GenericIdentity(("{0}", )); = ; me = me; d = d; le = le; } public bool IsInRole(string role) { if ((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 c;using ;using ;/*---------------------------------------------------------------- Copyright (C) 2017 陈卧龙

⽂件名:CS ⽂件功能描述:Token相关操作----------------------------------------------------------------*/namespace CS{ public class CommonToken { public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥 属于私钥 public static string GetToken(TokenInfo M) { var jwtcreated = (( - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var jwtcreatedOver = ((rs(2) - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5);//TOKEN声明周期⼆⼩时 var payload = new Dictionary { {"iss", },//⾮必须。issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。 {"iat", jwtcreated},//⾮必须。issued at。 token创建时间,unix时间戳格式 {"exp", jwtcreatedOver},//⾮必须。expire 指定token的⽣命周期。unix时间戳格式 {"aud", },//⾮必须。接收该JWT的⼀⽅。 {"sub", },//⾮必须。该JWT所⾯向的⽤户 {"jti", },//⾮必须。JWT ID。针对当前token的唯⼀标识 {"UserId", },//⾃定义字段 ⽤于存放当前登录⼈账户信息 {"UserName", me},//⾃定义字段 ⽤于存放当前登录⼈账户信息 {"UserPwd", d},//⾃定义字段 ⽤于存放当前登录⼈登录密码信息 {"UserRole", le},//⾃定义字段 ⽤于存放当前登录⼈登录权限信息 }; return (payload, SecretKey, 256); } } public class TokenInfo { public TokenInfo() { iss = "签发者信息"; aud = ""; sub = ""; jti = ng("yyyyMMddhhmmss"); UserId = 1; UserName = ""; UserPwd = "jack123456"; UserRole = "strator"; } // 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 c;using ;using ;using ;using ;using 2._0;namespace llers{ public class MangerApiController : ApiController { [ApiActionAuth] [HttpGet] public string GetStr() { int UserId = ; string UserName = me; string UserPwd = d; string UserRole = le; return "当前登录的第三⽅⽤户信息如下,UserId:" + UserId + ",UserName:" + UserName + ",UserPwd:" + UserPwd + ",UserRole:" + UserRole; } }} OK,有了上述代码我们就可以模拟TOKEN验证了,模拟步骤如下:/3.5、模拟TOKEN验证:3.5.1、⽣成TOKEN,代码如下:using System;using c;using ;using ;using ;using trols;using CS;namespace TestForToken{ public partial class WebForm1 : { protected void Page_Load(object sender, EventArgs e) { (en(new TokenInfo())); } }}⽣成的TOKEN为:3MiOiLnrb7lj5HogIXkv6Hmga8iLCJpYXQiOjE1MDk2OTEyODQsImV4cCI6MTUwOTY5ODQ4NCwiYXVkIjoiaHR0cDovL2V4YW1wbGUuY29tIiwic3Vi3.5.2、将获取的TOKEN(有效期两个⼩时)返回⾄客户端,客户端将获取的TOKEN放在 请求头 Headers 中,模拟请求如下(PostMan):OK,将上述TOKEN随便去掉⼀个字母,请求结果如下:

过期的TOKEN,请求如下:

OK,关于TOKEN更详细的验证,还需要⼤家⾃⾏完善,本篇博客我仅仅只验证了TOKEN是否正确,没有作进⼀步的验证,⼤家可根据项⽬需求,主动完善TOKEN验证代码。 例如:读取TOKEN存放的⽤户名,密码,⾓⾊等信息再作数据库验证。或者如同上述的MVC 控制器控制,验证⾓⾊等信息,总之,,,,,,,不写了,太累,还有任务没完成呢。哈!见谅!项⽬源码位置:

2023年6月20日发(作者:)

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:⾸先引⼊en⽣成的具体代码如下:using System;using c;using ;using ;/*---------------------------------------------------------------- Copyright (C) 2017 陈卧龙

⽂件名:CS ⽂件功能描述:Token相关操作----------------------------------------------------------------*/namespace CS{ public class CommonToken { public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥 属于私钥 public static string GenToken(TokenInfo M) { var jwtcreated = (( - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var jwtcreatedOver = ((rs(2) - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var payload = new Dictionary { {"iss", },//⾮必须。issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。 {"iat", jwtcreated},//⾮必须。issued at。 token创建时间,unix时间戳格式 {"exp", jwtcreatedOver},//⾮必须。expire 指定token的⽣命周期。unix时间戳格式 {"aud", },//⾮必须。接收该JWT的⼀⽅。 {"sub", },//⾮必须。该JWT所⾯向的⽤户 {"jti", },//⾮必须。JWT ID。针对当前token的唯⼀标识 {"UserName", me},//⾃定义字段 ⽤于存放当前登录⼈账户信息 {"UserPwd", d},//⾃定义字段 ⽤于存放当前登录⼈登录密码信息 {"UserRole", le},//⾃定义字段 ⽤于存放当前登录⼈登录权限信息 }; return (payload, SecretKey, 256); } } public class TokenInfo { public TokenInfo() { iss = "签发者信息"; aud = ""; sub = ""; jti = ng("yyyyMMddhhmmss"); UserName = ""; UserPwd = "jack123456"; UserRole = "strator"; } // 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中,也就是:s,那么如何接收请求头中的Token呢?接收到Token后如何验证呢?验证TOKEN时就需要构建 MVC Action 过滤器(AuthorizeAttribute)了,不过在构建 AuthorizeAttribute 之前,有必要对 AuthorizeAttribute 说明下,如下:⾸先,AuthorizeAttribute 类位于 命名空间下及命名空间下,⼀般情况下,如果你需要对C# MVC 控制器的访问作认证与授权,你需要⽤命名空间下的 AuthorizeAttribute ,如果你需要对C# API 控制器的访问作认证与授权,你需要⽤ 命名空间下的 AuthorizeAttribute !OK,知道了上述两种不同命名空间下的 AuthorizeAttribute ,下⾯以范例作为说明:2.1、⾃定义MVC ACTION 登录授权验证,(由于本篇博客主讲 Token 的验证与实现,因此,关于MVC 登录验证只做代码说明:)2.1.1、新建⼀个MVC控制器,命名为BaseController,代码如下:using System;using c;using ;using ;using ;using ty;namespace llers{ public class BaseController : Controller { #region 退出登录 ///

/// 退出登录 /// public void ClearLogin() { FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, "", , utes(-30), false, "", "/" ); //.ASPXAUTH string encryptedTicket = t(authTicket); okie authCookie = new okie(ookieName, encryptedTicket); (authCookie); } #endregion #region ⾃定义过滤器 /// /// ⾃定义过滤器 /// /// protected override void OnActionExecuting(ExecutingContext filterContext) { string cookieName = ookieName; HttpCookie authCookie = s[cookieName]; FormsAuthenticationTicket authTicket = null; try { authTicket = t(); } catch (Exception ex) { return; } if (authTicket != null && enticated) { string UserName = ;

onExecuting(filterContext); } else { Content("", "text/html"); //ct("/Home/Logins"); } } #endregion #region 读取错误信息 ///

/// 读取错误信息 /// /// public string GetError() { var errors = ; foreach (var item in errors) { foreach (var item2 in ) { if (!OrEmpty(essage)) { return essage; } } } return ""; } #endregion }}2.2.2、新建⼀个MVC控制器,命名为HomeController,代码如下:using System;using c;using ;using ;using ;using ;namespace llers{ public class HomeController : BaseController { public ActionResult Login() { ClearLogin(); string HX_userName = kie("HX_userName"); string HX_userPwd = kie("HX_userPwd"); _userName = HX_userName; _userPwd = HX_userPwd; return View(); } [HttpPost] public object UserLogin(LoginsModel LoginMol) { if (d)//是否通过Model验证 { return ction(); } else { return GetError(); } } }}2.2.3、新建⼀个登录实体类,命名为:LoginsModel,代码如下:using System;using c;using notations;using ;using ;using ty;namespace { 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(rd, ErrorMessage = "密码格式不正确")] public string UserPwd { get; set; } public bool remember { get; set; } public string LoginAction() { lock (LOCK) { string userRole = ; //数据库操作代码 int UserId = 0; if (UserName == "" && UserPwd == "") { UserId = 1; userRole = "strator"; } else if (UserName == "" && UserPwd == "") { UserId = 2; userRole = ""; } else { UserId = 3; userRole = ""; } if (UserId != 0) { if (remember) { kie("HX_userName", UserName, 7); kie("HX_userPwd", UserPwd, 7); } FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, UserName + "_" + UserId, , utes(30), false, userRole, "/" ); //.ASPXAUTH string encryptedTicket = t(authTicket); okie authCookie = new okie(ookieName, encryptedTicket); (authCookie); return "strator"; } else { return "账户密码不存在"; } } } }}2.2.4、修改你的⽂件,修改代码如下:using System;using c;using ;using pal;using ;using ;using ;using zation;using g;using ty;namespace TestForToken{ // 注意: 有关启⽤ IIS6 或 IIS7 经典模式的说明, // 请访问 /?LinkId=9394801 public class MvcApplication : plication { protected void Application_Start() { erAllAreas(); er(uration); erGlobalFilters(s); erRoutes(); erBundles(s); } /// /// 登录验证、s授权 /// /// /// protected void Application_AuthenticateRequest(Object sender, EventArgs e) { string cookieName = ookieName; HttpCookie authCookie = s[cookieName]; FormsAuthenticationTicket authTicket = null; try { authTicket = t(); } catch (Exception ex) { return; } string[] roles = (','); FormsIdentity id = new FormsIdentity(authTicket); GenericPrincipal principal = new GenericPrincipal(id, roles); = principal;//存到中    

} }}2.2.5、公共访问类CommonCS部分代码如下:using System;using c;using ;using tions;using ;using rExpressions;using ;using g;namespace TestForToken{ public class CommonMethod { #region cookie操作 ///

/// Cookies赋值 /// /// 主键 /// 键值 /// 有效天数 /// public static bool setCookieForMIn(string strName, string strValue, int Mintius) { try { HttpCookie Cookie = new HttpCookie(strName); // = ".";//当要跨域名访问的时候,给cookie指定域名即可,格式为. s = utes(Mintius); = strValue; (Cookie); return true; } catch { return false; } } /// /// Cookies赋值 /// /// 主键 /// 键值 /// 有效天数 /// public static bool setCookie(string strName, string strValue, int strDay) { try { HttpCookie Cookie = new HttpCookie(strName); // = ".";//当要跨域名访问的时候,给cookie指定域名即可,格式为. s = s(strDay); = strValue; (Cookie); return true; } catch { return false; } } /// /// 读取Cookies /// /// 主键 /// public static string getCookie(string strName) { HttpCookie Cookie = s[strName]; if (Cookie != null) { return ng(); } else { return null; } } /// /// 删除Cookies /// /// 主键 /// public static bool delCookie(string strName) { try { HttpCookie Cookie = new HttpCookie(strName); // = ".";//当要跨域名访问的时候,给cookie指定域名即可,格式为. s = s(-1); (Cookie); return true; } catch { return false; } } #endregion }}2.2.6、公共Token⽣成类代码如下:using System;using c;using ;using ;/*---------------------------------------------------------------- Copyright (C) 2017 陈卧龙

⽂件名:CS ⽂件功能描述:Token相关操作----------------------------------------------------------------*/namespace CS{ public class CommonToken { public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥 属于私钥 public static string GenToken(TokenInfo M) { var jwtcreated = (( - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var jwtcreatedOver = ((rs(2) - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var payload = new Dictionary { {"iss", },//⾮必须。issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。 {"iat", jwtcreated},//⾮必须。issued at。 token创建时间,unix时间戳格式 {"exp", jwtcreatedOver},//⾮必须。expire 指定token的⽣命周期。unix时间戳格式 {"aud", },//⾮必须。接收该JWT的⼀⽅。 {"sub", },//⾮必须。该JWT所⾯向的⽤户 {"jti", },//⾮必须。JWT ID。针对当前token的唯⼀标识 {"UserName", me},//⾃定义字段 ⽤于存放当前登录⼈账户信息 {"UserPwd", d},//⾃定义字段 ⽤于存放当前登录⼈登录密码信息 {"UserRole", le},//⾃定义字段 ⽤于存放当前登录⼈登录权限信息 }; return (payload, SecretKey, 256); } } public class TokenInfo { public TokenInfo() { iss = "签发者信息"; aud = ""; sub = ""; jti = ng("yyyyMMddhhmmss"); UserName = ""; UserPwd = "jack123456"; UserRole = "strator"; } // 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、新建⼀个登录页⾯,代码如下:@{ Layout = null;}

账户登录

2.2.8、新建⼀个登录验证属性,继承⾃:izeAttribute,代码如下:(千呼万唤始出来啊......~_~)using System;using c;using ;using pal;using ;using llers;using ;using ty;namespace 2._0{ public class MvcActionAuth : AuthorizeAttribute { public string[] AuthorizeRoleAry = new string[] { "", "", "strator" };//本系统允许的⾓⾊ 普通⽤户 会员 超级管理员 ///

/// ⾃定义 MVC 控制前访问权限验证 /// /// public override void OnAuthorization(izationContext filterContext) { string Role = ; string controllerName = llerName; string actionName = Name; //数据库验证当前Controller及Action允许访问的权限 //简单模拟 读取数据库 if (controllerName == "Manger" && actionName == "Index") { //得到允许访问 Manger/Index 的权限值 Role = "strator,"; } // string cookieName = ookieName; HttpCookie authCookie = s[cookieName]; FormsAuthenticationTicket authTicket = null; try { authTicket = t(); } catch (Exception ex) { return; } string[] roles = (','); string NowRole = ; foreach (var item in roles) { NowRole += item; } if (!ns(NowRole)) //没有权限访问当前控制器 ACtion { ct("/Home/Login"); }

orization(filterContext); } }}2.2.9、新建⼀个MVC 控制器 ,命名为:MangerController,代码如下:

上述代码就不做演⽰了,⼤致过程是这样的:Manger/Index的访问权限如下:

登录⽤户:

上述截图已经很清晰了,不再作重复说明。OK,上述代码便是整个MVC 控制器 登录验证/授权认证的全部代码。下⾯我们请出本⽂终极BOSS,如果接收并解析验证接收的TOKEN。 3、下⾯介绍webAPI Controller 的认证授权3.1、⾸先,我们⾃定义⼀个继承⾃ 命名空间下的AuthorizeAttribute 属性来解析并验证TOKEN代码如下:using System;using c;using ;using ;using ;using ;using ;using llers;using CS;namespace 2._0{ public class ApiActionAuth : AuthorizeAttribute { public override void OnAuthorization(HttpActionContext context) { var authHeader = rDefault(a => == "ApiAuthorization");//获取接收的Token if (s == null || !() || == null || OrEmpty(rDefault())) { Throw401Exception(context, "NoToken"); return; }

var sendToken = rDefault(); //url获取token

var now = (( - new DateTime(1970, 1, 1, 0, 0, 0, )).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⽤户数据放到 ⾥ ClientUserData clientUserData = new ClientUserData() { UserId = UserId, UserName = UserName, UserPwd = UserPwd, UserRole = UserRole }; if (t != null) { = new UserPrincipal(clientUserData); } } private static IDictionary DecodeToken(string token) { try { var dictPayload = ToObject(token, Key) as IDictionary; return dictPayload; } catch (Exception ex) { return null; } } private static void Throw401Exception(HttpActionContext actionContext, string exceptionString) { var response = se; throw new HttpResponseException( ErrorResponse(orized, exceptionString ?? "Unauthorized")); } private static string RequestToString(HttpRequestMessage request) { var message = new StringBuilder(); if ( != null) (); if (tUri != null) (" ").Append(tUri); return ng(); } }}3.2、新增⼀个存储解析Token结果的类,命名为,代码如下:using System;using c;using ;using pal;using ;namespace 2._0{ public class SysHelper { public static UserPrincipal CurrentPrincipal { get { return as UserPrincipal; } } } public class UserPrincipal : ClientUserData, IPrincipal { public IIdentity Identity { get; private set; } public string[] Roles { get; set; } public UserPrincipal(ClientUserData clientUserData) { ty = new GenericIdentity(("{0}", )); = ; me = me; d = d; le = le; } public bool IsInRole(string role) { if ((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 c;using ;using ;/*---------------------------------------------------------------- Copyright (C) 2017 陈卧龙

⽂件名:CS ⽂件功能描述:Token相关操作----------------------------------------------------------------*/namespace CS{ public class CommonToken { public static string SecretKey = "This is a private key for Server";//这个服务端加密秘钥 属于私钥 public static string GetToken(TokenInfo M) { var jwtcreated = (( - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5); var jwtcreatedOver = ((rs(2) - new DateTime(1970, 1, 1, 0, 0, 0, )).TotalSeconds + 5);//TOKEN声明周期⼆⼩时 var payload = new Dictionary { {"iss", },//⾮必须。issuer 请求实体,可以是发起请求的⽤户的信息,也可是jwt的签发者。 {"iat", jwtcreated},//⾮必须。issued at。 token创建时间,unix时间戳格式 {"exp", jwtcreatedOver},//⾮必须。expire 指定token的⽣命周期。unix时间戳格式 {"aud", },//⾮必须。接收该JWT的⼀⽅。 {"sub", },//⾮必须。该JWT所⾯向的⽤户 {"jti", },//⾮必须。JWT ID。针对当前token的唯⼀标识 {"UserId", },//⾃定义字段 ⽤于存放当前登录⼈账户信息 {"UserName", me},//⾃定义字段 ⽤于存放当前登录⼈账户信息 {"UserPwd", d},//⾃定义字段 ⽤于存放当前登录⼈登录密码信息 {"UserRole", le},//⾃定义字段 ⽤于存放当前登录⼈登录权限信息 }; return (payload, SecretKey, 256); } } public class TokenInfo { public TokenInfo() { iss = "签发者信息"; aud = ""; sub = ""; jti = ng("yyyyMMddhhmmss"); UserId = 1; UserName = ""; UserPwd = "jack123456"; UserRole = "strator"; } // 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 c;using ;using ;using ;using ;using 2._0;namespace llers{ public class MangerApiController : ApiController { [ApiActionAuth] [HttpGet] public string GetStr() { int UserId = ; string UserName = me; string UserPwd = d; string UserRole = le; return "当前登录的第三⽅⽤户信息如下,UserId:" + UserId + ",UserName:" + UserName + ",UserPwd:" + UserPwd + ",UserRole:" + UserRole; } }} OK,有了上述代码我们就可以模拟TOKEN验证了,模拟步骤如下:/3.5、模拟TOKEN验证:3.5.1、⽣成TOKEN,代码如下:using System;using c;using ;using ;using ;using trols;using CS;namespace TestForToken{ public partial class WebForm1 : { protected void Page_Load(object sender, EventArgs e) { (en(new TokenInfo())); } }}⽣成的TOKEN为:3MiOiLnrb7lj5HogIXkv6Hmga8iLCJpYXQiOjE1MDk2OTEyODQsImV4cCI6MTUwOTY5ODQ4NCwiYXVkIjoiaHR0cDovL2V4YW1wbGUuY29tIiwic3Vi3.5.2、将获取的TOKEN(有效期两个⼩时)返回⾄客户端,客户端将获取的TOKEN放在 请求头 Headers 中,模拟请求如下(PostMan):OK,将上述TOKEN随便去掉⼀个字母,请求结果如下:

过期的TOKEN,请求如下:

OK,关于TOKEN更详细的验证,还需要⼤家⾃⾏完善,本篇博客我仅仅只验证了TOKEN是否正确,没有作进⼀步的验证,⼤家可根据项⽬需求,主动完善TOKEN验证代码。 例如:读取TOKEN存放的⽤户名,密码,⾓⾊等信息再作数据库验证。或者如同上述的MVC 控制器控制,验证⾓⾊等信息,总之,,,,,,,不写了,太累,还有任务没完成呢。哈!见谅!项⽬源码位置: