过滤器实现Token验证(登录验证+过期验证)---简单的实现
功能:登录验证+过期验证+注销清除cookie+未注销下关闭或刷新浏览器仍可直接访问action
概述:token只存在客户端cookie,后端AES加密+解密+验证,每一次成功访问action都会刷新token包括过期时间
1.过滤器
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Mvc;
namespace TokenTest.MyActionFilter
{
/// <summary>
/// <param name="Die_Time">Die_Time//设置token过期时间小于7days</param>
/// <param name="Jump_Page">Jump_Page//设置token验证失败后跳转页面如/Login/Index;可携带参数/Login/Index?******</param>
/// </summary>
public class Token_Filter:ActionFilterAttribute//继承ActionFilterAttribute类
{
public int Die_Time { get; set;}//设置token过期时间<7days
public string Jump_Page { get; set; }//设置token验证失败后跳转页面如/Login/Index;可携带参数/Login/Index?******
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var token = HttpContext.Current.Request.Cookies["Token"];
if (token==null)
{
HttpContext.Current.Response.Write("<script language='javascript'>alert('您未登陆,请先登陆!');location.href='" + Jump_Page + "' ;</script>");
}
else
{
string U_ID = AESDecrypt(token.Value.ToString(), "jjq").Split('_')[0];
DateTime Token_Time = Convert.ToDateTime(AESDecrypt(token.Value.ToString(), "jjq").Split('_')[1]);
//检验过期时间;token理论上验证有效期:Die_Time<7天/////每次加载过滤action都会重新设置时间(可改)
if (Token_Time.AddDays(Die_Time) < DateTime.Now)
{
HttpContext.Current.Response.Write("<script language='javascript'>alert('登陆过期,请重新登录!');location.href='" + Jump_Page + "' ;</script>");
}
else
{
//完全验证通过后重新改写token并覆写在cookie里
Set_Token(U_ID);
}
}
}
public static void Set_Token(string user_name)
{
var Token = AESEncrypt(user_name + "_" + DateTime.Now.ToString() + "_" + Guid.NewGuid(), "jjq");//Token加密;;jjq加密密匙
HttpContext.Current.Response.Cookies["Token"].Value = Token;
HttpContext.Current.Response.Cookies["Token"].Expires = DateTime.Now.AddDays(7);//设置Token客户端保留时间7天
}
#region
/// <summary>
/// 加密解密功能代码片段
/// </summary>
//AES密钥向量
private static readonly byte[] _aeskeys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
/// <summary>
/// AES加密
/// </summary>
/// <param name="encryptStr">加密字符串</param>
/// <param name="encryptKey">密钥</param>
/// <returns></returns>
public static string AESEncrypt(string encryptStr, string encryptKey)
{
if (string.IsNullOrWhiteSpace(encryptStr))
return string.Empty;
encryptKey = SubString(encryptKey, 0, 32);
encryptKey = encryptKey.PadRight(32, ' ');
//分组加密算法
SymmetricAlgorithm des = Rijndael.Create();
byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptStr);//得到需要加密的字节数组
//设置密钥及密钥向量
des.Key = Encoding.UTF8.GetBytes(encryptKey);
des.IV = _aeskeys;
byte[] cipherBytes = null;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
cipherBytes = ms.ToArray();//得到加密后的字节数组
cs.Close();
ms.Close();
}
}
return Convert.ToBase64String(cipherBytes);
}
/// <summary>
/// AES解密
/// </summary>
/// <param name="decryptStr">解密字符串</param>
/// <param name="decryptKey">密钥</param>
/// <returns></returns>
public static string AESDecrypt(string decryptStr, string decryptKey)
{
if (string.IsNullOrWhiteSpace(decryptStr))
return string.Empty;
decryptKey = SubString(decryptKey, 0, 32);
decryptKey = decryptKey.PadRight(32, ' ');
byte[] cipherText = Convert.FromBase64String(decryptStr);
SymmetricAlgorithm des = Rijndael.Create();
des.Key = Encoding.UTF8.GetBytes(decryptKey);
des.IV = _aeskeys;
byte[] decryptBytes = new byte[cipherText.Length];
using (MemoryStream ms = new MemoryStream(cipherText))
{
using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read))
{
cs.Read(decryptBytes, 0, decryptBytes.Length);
cs.Close();
ms.Close();
}
}
return Encoding.UTF8.GetString(decryptBytes).Replace("\0", "");//将字符串后尾的'\0'去掉
}
public static string SubString(string sourceStr, int startIndex, int length)
{
if (!string.IsNullOrEmpty(sourceStr))
{
if (sourceStr.Length >= (startIndex + length))
return sourceStr.Substring(startIndex, length);
else
return sourceStr.Substring(startIndex);
}
return "";
}
#endregion
}
}
2.使用方法
1.需要过滤的Controller中引用(注意给参数)
using System.Web.Mvc;
using TokenTest.MyActionFilter;
namespace TokenTest.Controllers
{
public class adminController : Controller
{
// GET: admin
[Token_Filter(Die_Time=3,Jump_Page = "/Login/Index")]
public ActionResult Index()
{
return View();
}
}
}
2.LoginController中引用Token_Filter.Set_Token()方法;激活设置token+注销按钮(清除cookie)
using System;
using System.Web.Mvc;
using TokenTest.MyActionFilter;
namespace TokenTest.Controllers
{/// <summary>
/// ////////////////////////////////////////////////
/// </summary>
public class LoginController : Controller
{
// GET: Login
public ActionResult Index()
{
return View();
}
public ActionResult Logout()
{
//注销按钮---清除cookie
Response.Cookies["Token"].Expires = DateTime.Now.AddDays(-1);
return View("Index");
}
public ActionResult Login()
{
var get_name = Request["name"];
var get_pwd = Request["pwd"];
JJQPractice visitor = JJQPractice.SingleOrDefault(new { name = get_name });//得到对应输入的账号的集
if (visitor != null)//验证输入的账号是否存在
{
if (visitor.pwd == get_pwd)//验证密码是否正确
{
Token_Filter.Set_Token(get_name);
return RedirectToAction("Index", "admin"); //密码正确后跳转到查询视图
}
else
{
Response.Write("登录失败!密码错误.");
return View("Index");
}
}
else
{
Response.Write("登录失败,用户名不存在.");
return View("Index");
}
}
}
}
<h2>Logn-Index</h2>
<br><br>
<form action="/Login/Login" method="post">
姓名:<input type="text" name="name"/><br><br>
密码:<input type="text" name="pwd"/><br><br>
<input type="submit" value="提交"/><br><br>
</form>
<h2>Index</h2>
<form action="/admin/Index" method="post">
<input name="h" value="6666"/>
<input type="submit" value="按钮"/><br /><br />
</form>
<form action="/Login/Logout" method="post">
<input type="submit" value="注销_清除cookie" />
</form>
过滤器实现Token验证(登录验证+过期验证)---简单的实现的更多相关文章
- MVC 自定义过滤器/特性来实现登录授权及验证
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 最近在做自学MVC,遇到的问题很多,索性一点点总结 ...
- SpringBoot实现基于token的登录验证
一.SpringBoot实现基于token的登录验证 基于token的登录验证实现原理:客户端通过用户名和密码调用登录接口,当验证数据库中存在该用户后,将用户的信息按照token的生成规则,生成一个字 ...
- Java实现token的生成与验证-登录功能
一.token与cookie相比较的优势1.支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的: 2.无状态化,服务端无需存储token,只需要验证token信息是否正确即可,而 ...
- app与php后台接口登录认证、验证(seesion和token)
简要:随着电商的不断发展,APP也层次不穷,随着科技的发展主要登录形式(微信.QQ.账号/密码):为此向大家分享一下"app与php后台接口登录认证.验证"想法和做法:希望能够帮助 ...
- [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件
没有任何注释,表怪我(¬_¬) 更新: 2016.05.29: 将AuthorizationServer和ResourceServer分开配置 2016.05.29: Token获取采用Http Ba ...
- jwt验证登录信息
为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...
- Python Django缓存,信号,序列化,文件上传,Ajax登录和csrf_token验证
本节内容 models操作 Django的缓存 请求方式 序列化 Form 配合Ajax实现登录认证 上传文件 Ajax csrf_token验证方式 1 models操作 单表查询: curd(增 ...
- vue拦截器实现统一token,并兼容IE9验证
项目中使用vue搭建前端页面,并通过axios请求后台api接口,完成数据交互.如果验证口令token写在在每次的接口中,也是个不小的体力活,而且也不灵活.这里分享使用vue自带拦截器,给每次请求的头 ...
- [置顶] Web用户的身份验证及WebApi权限验证流程的设计和实现 (不是Token驗證!!!不是Token驗證!!!都是基於用户身份的票据信息驗證!!!)
转发 http://blog.csdn.net/besley/article/details/8516894 不是Token驗證!!!不是Token驗證!!!都是基於用户身份的票据信息驗證!!! [ ...
随机推荐
- [E2E_L7 51CTO]初步接触OpenVINO提供的例子(win+vs)
一.例子编译 1.运行 C:\Program Files (x86)\IntelSWTools\openvino_2019.1.148\bin\setupvars.bat 这步需要win平台下安装py ...
- [转]c++ pthread 多线程简介
链接:https://blog.csdn.net/u013894427/article/details/83827173 pthread 入口函数类型说明void * func1(void * t)v ...
- Mac 上ssh远程连接Linux服务器提示Host key verification failed.
当我们对重装远程服务器的时候会出现Host key verification failed问题 解决办法: rm -rf ~/.ssh/known_hosts 重新ssh连接,OK!
- Java12新特性 -- JVM 常量 API
Java 12 中引入 JVM 常量 API,用来更容易地对关键类文件 (key class-file) 和运行时构件(artefact)的名义描述 (nominal description) 进行建 ...
- Redis 密码设置 及 带密码访问
转: Redis 密码设置 如果不加密码,默认只能本机访问,加密码也是为了安全考虑 1.进入Redis 的安装目录,找到redis.conf文件.用vi命令打开文件 输入 / requirepass ...
- ResponseBody和文件上传
SpringMVC默认使用MappingJacksonHttpMessageConverter对json数据进行转换 <dependency> <groupId>com.fas ...
- IDEA进行activiti-archetype-unittest脚手架的安装
官网:https://www.activiti.org/ 第一步:下载activiti源码(https://github.com/Activiti/Activiti/tags) 第二步:在termin ...
- 高级UI-UI绘制流程
UI的绘制流程和事件分发,属于Android里面的重点内容,在做自定义UI的时候,更是应该了解UI的绘制流程是如何的,此篇文章就是说明UI的绘制流程,事件分发前面已经详细讲过了 UI绘制流程探索 这里 ...
- 笨方法学Python摘记(1)
编程新手所需的最重要的三种技能:读和写.注重细节.发现不同 不要复制粘贴! #-*-codinig:utf-8 -*- (脚本使用unicode UTF-8) 书写习惯:操作符的两边加上空格,提高代 ...
- foreach引用坑
先看下面代码 $arr1 = [1, 2]; foreach($arr1 as $key => $value) { $value = $value + 1; } var_dump($key, $ ...