【ASP.NET MVC】使用动软(四)(12)

一、筛选器类和Cookie实现路由

需解决的问题:

网站登录往往需要用户名+密码验证,为避免重复验证,一般采用Cookie 、Session等技术来保持用户的登录状态:

Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;

Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式

从上解释可见,Cookie 比 Session 更简单,也不占用服务器的资源。

ActionFilterAttribute + Cookie 可以解决 以上问题:

首先,在工程中新建一个空目录(名称自取):

然后,在目录中添加一个类 UserCookie 负责对用户登录信息的Cookie相应操作:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
namespace ManageSysetm.Tools
{
    public class UserCookie
    {
        public static T JsonDeserialize<T>(string jsonString)
        {
            return JsonConvert.DeserializeObject<T>(jsonString);
        }

        public static string ToJson(object obj)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            return JsonConvert.SerializeObject(obj);
        }
        public static void WriteCookie(Maticsoft.Model.user mod)
        {            
            FormsAuthentication.SetAuthCookie(ToJson(mod), true, FormsAuthentication.FormsCookiePath);
            //把用户对象保存在票据里                
            FormsAuthenticationTicket Ticket = new FormsAuthenticationTicket(1, mod.userName, DateTime.Now, DateTime.Now.AddTicks(FormsAuthentication.Timeout.Ticks), false, ToJson(mod));
            //加密票据
            string hashTicket = FormsAuthentication.Encrypt(Ticket);
            HttpCookie userCookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashTicket);
            userCookie.Expires.AddHours(3);
            System.Web.HttpContext.Current.Response.Cookies.Add(userCookie);
        }

        public static Maticsoft.Model.user ReadCookie()
        {
            try
            {
                var cookie = System.Web.HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName]; //的到Cookie
                if (cookie == null)
                    return null;
                var ticket = FormsAuthentication.Decrypt(cookie.Value); //解密票据
                string str = ticket.UserData;
                return JsonDeserialize<Maticsoft.Model.user>(str);
            }
            catch
            {
                return null;
            }
        }

        public static void ReMoveCookie()
        {
            FormsAuthentication.SignOut();
        }
   }
}

说明:

1、添加了序列化的Json处理函数,关于JSON可以参考前面的介绍;

2、读写Cookie:对输入的Model 序列化 (ToJson) 成字符串,然后写入票据,读的过程正好相反

再添加筛选器类:IsLogin 继承于 ActionFilterAttribute

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace ManageSysetm.Tools
{
    public class IsLogin : ActionFilterAttribute
    {
        //当方法执行时       
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            try
            {              
                var isLogin = UserCookie.ReadCookie();
                if (isLogin == null)
                {
                    filterContext.Result = new RedirectResult("/Home/login");                 
                }
            }
            catch
            {
                filterContext.Result = new RedirectResult("/Home/login");               
            }
            base.OnActionExecuting(filterContext);
        }
        //当方法执行完毕
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
        }
    }
}

逻辑比较简单:判断是否存在Cookie,不存在的时候或者异常时跳转到登录页面,否则正常通过。

二、使用

可以用"帽子"的方法来实现筛选:

在默认的路由 Index上添加 筛选器 IsLogin ,则在该Action执行前先进行筛选器判断:取Cookie,没有则返回登录页面,否则正常进入Index 。

拓展:

既然可以添加 筛选器 IsLogin ,那么是否也可以添加 筛选器 IsAdmin (名称自取) ? ------这样可以根据不同用户角色筛选进入不同的页面。

当然是可以的,解决思路无非就是加入用户Cookie中身份的判断逻辑!

三、补充

数据表中用明文记录用户的密码是不可取的,一旦数据表被曝光后,用户的角色就能够被人使用。比如:数据库管理人员可以利用数据表中的用户名和密码直接进行用户角色登录!

解决方法是加密:(贴几个实用函数,可以放入某个工具类中)

 private static string Key
        {
            get { return @")O[NB]6,YF}+efcaj{+oESb9d8>Z'e9M"; }
        }
        private static string IV
        {
            get { return @"L+\~f4,Ir)b$=pkf"; }
        }
        public static string Encrypt(string pwd)//加密
        {

            byte[] bKey = Encoding.UTF8.GetBytes(Key);
            byte[] bIV = Encoding.UTF8.GetBytes(IV);
            byte[] byteArray = Encoding.UTF8.GetBytes(pwd);//将字符串转换为字节序列

            string encrypt = null;
            Rijndael aes = Rijndael.Create();
            using (MemoryStream mStream = new MemoryStream())//创建内存流对象
            {
                using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateEncryptor(bKey, bIV), CryptoStreamMode.Write))//创建加密流对象
                {
                    cStream.Write(byteArray, 0, byteArray.Length);//向加密流中写入字节序列
                    cStream.FlushFinalBlock();//将数据压入基础流,用缓冲区的当前状态更新基础数据源或储存库,随后清除缓冲区。
                    encrypt = Convert.ToBase64String(mStream.ToArray());//从内存流中获取字节序列,并返回加密后的字符串
                }
            }
            aes.Clear();
            return encrypt;

        }
       
        public static string AESDecrypt(string encryptStr)
        {
            byte[] bKey = Encoding.UTF8.GetBytes(Key);
            byte[] bIV = Encoding.UTF8.GetBytes(IV);
            byte[] byteArray = Convert.FromBase64String(encryptStr);

            string decrypt = null;
            Rijndael aes = Rijndael.Create();
            using (MemoryStream mStream = new MemoryStream())
            {
                using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(bKey, bIV), CryptoStreamMode.Write))
                {
                    cStream.Write(byteArray, 0, byteArray.Length);
                    cStream.FlushFinalBlock();
                    decrypt = Encoding.UTF8.GetString(mStream.ToArray());
                }
            }
            aes.Clear();
            return decrypt;
        }

使用方法比较简单:string s= UserCookie.Encrypt(password); //对密码加密处理

加密字符串,由此解决用户表密码信息的保护:

PS:

验证的时候不需要解密,用户输入的密码加密 与 数据表中字段匹配一下即可。

相关推荐
pouop8 分钟前
Linux进程信号保存/操作系统运行原理
运维·服务器
王解9 分钟前
一篇文章读懂 Prettier CLI 命令:从基础到进阶 (3)
前端·perttier
乐闻x15 分钟前
最佳实践:如何在 Vue.js 项目中使用 Jest 进行单元测试
前端·vue.js·单元测试
檀越剑指大厂29 分钟前
【Python系列】异步 Web 服务器
服务器·前端·python
我是Superman丶31 分钟前
【前端】js vue 屏蔽BackSpace键删除键导致页面后退的方法
开发语言·前端·javascript
楚疏笃31 分钟前
linux安全管理-账号口令
linux·服务器·安全
Hello Dam32 分钟前
基于 Spring Boot 实现图片的服务器本地存储及前端回显
服务器·前端·spring boot
LightOfNight33 分钟前
Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)
服务器·数据库·redis·分布式·后端·缓存·中间件
孤邑34 分钟前
【Linux】网络通信
linux·服务器·网络·笔记·学习
小仓桑34 分钟前
利用 Vue 组合式 API 与 requestAnimationFrame 优化大量元素渲染
前端·javascript·vue.js