MVC中Forms窗体验证及关于ActionFilterAttribute拦截器的实现

前言

认证和授权机制
认证是确定用户身份的过程。在用户通过了身份验证后,开发人员
就可以确定该用户是否有权继续操作。如果没有进行身份验证,就
不能进行实体的授权。
授权是确定已验证的用户是否有权访问应用程序中的某个部分、某
个点、或只访问应用程序提供的特定数据集。

今天分享关于.NET MVC中的Forms窗体登录验证,及ActionFilterAttribute角色拦截。登录方式可以为二种方式。
第一种为:form表单提交。
第二种:Ajax异步提交。好话不多说,直接上代码。

登录概要流程图

在这里插入图片描述

Web.Config配置

(1)在web.Config配置中的 system.web 节点内添加authentication认证节点。

(2)Mode : ASP.NET支持3种授权方法
                     ●Windows : IIS验证。在内联网环境中非常有用。
                     ●Passport :微软集中式身份验证, -次登录便可访问所有成员
站点,需要收费。
                     ●Forms:窗体验证,验证帐号/密码, Web编程最佳流行的验证方
式。
                     那这里我们选择Forms窗体验证。

(3)关于Forms节点中所用到的属性:
          ●name:是赋予Cookie的名字 用于在请求之间保存用户,默认值为.Aspxauth
          ●loginurl:需要处理验证的页面。我们这里是登录页面处理。如果没有找到有效的验证cookie 就指定重新定西的URL
          ●timeout:指定Cookie过期的时间(分钟) ,这里指定过期时间为20分钟。

 <system.web>
         <authentication mode="Forms">
             <forms name="auth" loginUrl="/Account/Login"   timeout="20" > </forms>
        </authentication>
  </system.web>

登录视图

(1)在视图中表单需要注意的是 action 提交地址。另外在控制器中,如果指定了提交方式,那一定注意method 的提交方式。且应该使用post。还有就是 用户框与密码框的name属性值。传递参数的命名为相关name值。

  <form class="layui-form" id="form" action="/Account/Login" method="post">
                    <label class="layui-form-label" >用户名</label>
                    <input type="text" name="LoginId" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" >
                    <label class="layui-form-label">密码</label>
                    <input type="password" name="LoginPWD" required lay-verify="required" placeholder="请输入密码" autocomplete="off" >
                    @*方式一,表单提交*@
                    <button class="layui-btn lg_btn" type="submit" lay-submit lay-filter="formDemo">立即登录</button>
  </form>

登录控制器

(1)通过视图用户输入的用户名以及密码,向数据库中用户表去查询并返回个人信息的实体类。

(2)判断个人的状态 status 是否 离职

(3)在登录密码成功且个人状态在职的情况下,开始创建票据。FormsAuthenticationTicket。参数为:版本号,用户名,票据创建日期,票据过期时间,是否持续票据,用户自定义数据 。

(4)在票据 FormsAuthenticationTicket 中的UserData只能放字符串类型,要是我们想把用户对象存储进去的话。可以将对象序列化成json格式字符串。要想使用的话,反序列化就好了。

(5) 对新建的票据 进行 加密票据 使用的方法 FormsAuthentication. Encrypt。 利用票据生成Cookie然后保存到Cookies。注意 Cookie的Key 指的是窗体验证的名字 FormsAuthentication.FormsCookieName

(5)跳转页面,这里为员工index页面。

        [HttpPost]
        public ActionResult Login(string LoginId, string LoginPWD)
        {
                                                //MD5加密
            LoginPWD = Converters.ToolMD5Encrypt(LoginPWD);
            employee employee = new employee();
            employee.Login_name = LoginId;
            employee.Login_pwd = LoginPWD;
            if (ES.LoginVilidate(employee) != null)
            {
                //通过输入的用户名和密码进行数据库匹配并返回实体信息
                employee SuccesEntity = ES.LoginVilidate(employee);
                if (SuccesEntity.Status == "1")
                {
                    ViewBag.LoginMesssage = "用户不存在";
                }
                else
                {
                    //创建一个授权对象类  存储相关信息
                    Authinfor AuthEntity = new Authinfor { Emp_id = SuccesEntity.Emp_id, Name = SuccesEntity.Name, Roles_name = SuccesEntity.Roles_name };
                    //序列化授权对象类,用于放入票据中的用户自定义事件
                    string userDataJson = JsonConvert.SerializeObject(AuthEntity);
                    FormsAuthenticationTicket Tick = new FormsAuthenticationTicket(
                      1,                                                                    //版本号
                      SuccesEntity.Name,                                                    //用户名
                      DateTime.Now,                                                         //创建票据日期
                      DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),    //票据持续时间
                      false,                                                                //是否持久性
                     userDataJson);                                                         //用户自定义存储数据
                    string eny = FormsAuthentication.Encrypt(Tick);                         //对创建好了的票据进行加密
                    //将票据保存在
                    HttpCookie HK = new HttpCookie(FormsAuthentication.FormsCookieName, eny);
                    Response.Cookies.Add(HK);
                    return Redirect("/Employees/index");
                }
            }
            else
            {
                ViewBag.LoginMesssage = "登录失败";
            }
            return View();
        }

注意:我这里因为注册员工的时候,密码采用的是MD5加密存储在数据库中。所以在判断员工输入密码是否正确的时候,需要再次MD5加密两边统一格式,然后在数据库中查询相关信息。

        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="value">要加密的字符串</param>
        /// <returns>加密好的字符串</returns>
        public static string ToolMD5Encrypt(string value)
        {
            try
            {
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] btSource = System.Text.Encoding.Default.GetBytes(value);
                byte[] btResult = md5.ComputeHash(btSource);
                string encryptData = "";
                for (int i = 0; i < btResult.Length; i++)
                {
                    encryptData += btResult[i].ToString("X");
                }
                return encryptData;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

那么以上就完成了窗体验证的流程了。接下来需要注意的一点是。要对哪一个视图页面进行需要验证才能访问呢?加入 [Authorize] 标志即可。

(1)登录控制器中,我是验证成功之后重定向地址为员工的index页面。所以我在 员工index控制器上面加个认证的标志 .

        // GET: Employees
        [CheckFilter("经理")]
        [Authorize]
        public ActionResult Index()
        {
            return View();
        }

(2)接下来将要完成角色拦截了。也就是说,不是每个页面,任何员工都能访问的。

(3)新建一个类,类名自定义,我这边为 CheckFilter。

(4)自定义拦截器,继承继承ActionFilterAttribute抽象类,重写其中需要的方法,来看下ActionFilterAttribute类的方法签并重写。
     ●OnActionExecuting:将要进入Action 时要处理的虚方法,这里可以对接收到的Request请求进行处理或拦截。
     ●OnActionExecuted:已进入Action 了,这里可以继续处理点事情或拦截
     ●OnResultExecuting:响应Result之前,这里可以继续处理点事情或拦截
     ●OnResultExecuted:响应Result完成之后,这里可以继续处理点事情或拦截

自定义拦截器类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using Newtonsoft.Json;
using Model.BusinessMsage;
namespace TestHoses.Code
{
 public class CheckFilter : ActionFilterAttribute
 {
     protected string Roles { get; set; }
     protected bool IsAjaxs { get; set; }

     /// <summary>
     /// 构造函数
     /// </summary>
     /// <param name="roles"></param>
     /// <param name="ajaxs"></param>
     public CheckFilter(string roles="", bool ajaxs = false)
     {
         Roles = roles;
         IsAjaxs = ajaxs;
     }


     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
         //判断当前请求类型是否为Ajax请求
         if (filterContext.HttpContext.Request.IsAjaxRequest())
         {
             this.IsAjaxs = true;
         }
     }


     public override void OnActionExecuted(ActionExecutedContext filterContext)
     {
         //获取当前验证成功票据中的用户自定义数据
         string userData = ((FormsIdentity)filterContext.HttpContext.User.Identity).Ticket.UserData;
         //反序列化获取对象
         Authinfor authinfor = JsonConvert.DeserializeObject<Authinfor>(userData);
         if (!authinfor.Roles_name.Split(',').Contains(Roles))
         {
             if (!IsAjaxs)
             {
                 filterContext.HttpContext.Response.Redirect("/Home/Error");
             }
             else
             {
                 filterContext.HttpContext.Response.Write("{\"meeage:\"你没权限\"}");
                 filterContext.HttpContext.Response.End();
             }
         }
         else {
             if (IsAjaxs) {
                 
                 filterContext.HttpContext.Response.Write("{\"meeage:\"true\"}");
                 filterContext.HttpContext.Response.End();
             }
         }
     }
 }
}

(1)封装字段属性,角色名,是否为ajax请求。

(2)在Action执行之前,对Request.IsAjaxRequest() 判断,判断当前是否为AJax请求。

(3)在Action执行之后,首先获取当前授权信息。也就是在票据中存储的userData。在存储之前,我们对他进行了序列化,所以读取的时候需要反序列化回来。

(4)判断该用户角色是否合法,是否为Ajax请求。

(5)那为什么这里要判断是否为ajax请求呢?因为我们要进行拦截处理的时候,我们需要重定向到其他页面地址,并告诉该用户没有权限访问。而Ajax属于局部刷新,Response.Redirect()重定向地址对它无效。因此我们需要判断请求类型,根据请求类型来处理一些事情。如果是Ajax请求,那么就返回指定信息或状态,在前端js中依据指定信息或状态来处理。非Ajax请求的话,就直接重定向相关页面地址,给出提示。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值