.Net MVC4 被坑心得(七)filter 身份验证

本文探讨了在MVC框架下如何通过自定义身份验证机制实现更灵活的授权控制,通过创建一个名为CheckAccessAttribute的特性,继承自AuthorizeAttribute并重写了核心验证逻辑。文章详细解释了如何通过自定义的验证方法`CheckCookiesVal`来检查用户的合法性,以及如何处理未授权的请求。此外,还介绍了如何通过属性修饰控制器或操作来忽略某些特定的验证规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    今天使用filter来做身份验证。

    filter本质也是attribute,需要继承自Attribute类,并指定作用范围。但是在mvc中,针对controller和action的filter,一般不直接继承自Attribute,而是继承自FilterAttribute或者其继承类。

    mvc4中实现了验证的特性,AuthorizeAttribute,实现了默认的身份验证。但是这个身份验证,是使用默认的数据连接,不能满足我们的实际要求。我们需要针对自己的系统,创建满足系统健全条件的身份验证。

    查看此特性的定义如下:

    // 摘要:
    //     表示一个特性,该特性用于限制调用方对操作方法的访问。
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
    {
        // 摘要:
        //     初始化 System.Web.Mvc.AuthorizeAttribute 类的新实例。
        public AuthorizeAttribute();

        // 摘要:
        //     获取或设置用户角色。
        //
        // 返回结果:
        //     用户角色。
        public string Roles { get; set; }
        //
        // 摘要:
        //     获取此特性的唯一标识符。
        //
        // 返回结果:
        //     此特性的唯一标识符。
        public override object TypeId { get; }
        //
        // 摘要:
        //     获取或设置授权用户。
        //
        // 返回结果:
        //     授权用户。
        public string Users { get; set; }

        // 摘要:
        //     重写时,提供一个入口点用于进行自定义授权检查。
        //
        // 参数:
        //   httpContext:
        //     HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。
        //
        // 返回结果:
        //     如果用户已经过授权,则为 true;否则为 false。
        //
        // 异常:
        //   System.ArgumentNullException:
        //     httpContext 参数为 null。
        protected virtual bool AuthorizeCore(HttpContextBase httpContext);
        //
        // 摘要:
        //     处理未能授权的 HTTP 请求。
        //
        // 参数:
        //   filterContext:
        //     封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。
        protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext);
        //
        // 摘要:
        //     在过程请求授权时调用。
        //
        // 参数:
        //   filterContext:
        //     筛选器上下文,它封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。
        //
        // 异常:
        //   System.ArgumentNullException:
        //     filterContext 参数为 null。
        public virtual void OnAuthorization(AuthorizationContext filterContext);
        //
        // 摘要:
        //     在缓存模块请求授权时调用。
        //
        // 参数:
        //   httpContext:
        //     HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。
        //
        // 返回结果:
        //     对验证状态的引用。
        //
        // 异常:
        //   System.ArgumentNullException:
        //     httpContext 参数为 null。
        protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);
    }
    他继承自FilterAttribute并实现了IAuthorizationFilter接口。IAuthorizationFilter接口很简单,只有一个OnAuthorization方法,就是身份验证的主题函数。实现IAuthorizationFilter必须实现该方法。

    AuthorizeAttribute特性实现了OnAuthorization方法,并将其声明为虚函数,理论上说,只需重写OnAuthorization方法,即可实现验证。但是如果那样,何必从AuthorizeAttribute继承,直接写一个特性继承自FilterAttribute,和IAuthorizationFilter接口就好了,又轻量。

    AuthorizeAttribute提供了3个属性和4个方法,4个方法全都是虚函数。我们重点关注AuthorizeCore和HandleUnauthorizedRequest。重载AuthorizeCore方法,实现判断用户是否合法,并返回bool,并重载HandleUnauthorizedRequest实现AuthorizeCore返回false时的处理。

具体代码:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    public class CheckAccessAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            return Access.CheckCookiesVal(httpContext.Request.Cookies);
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result = new HttpStatusCodeResult(403);
        }
    }

    若用[CheckAccess]修饰了controller,下面的action可以使用[AllowAnonymous]来忽略验证。

    其中,Access.CheckCookiesVal()是自己定义的用于验证的方法,具体定义如下:

 /// <summary>
    /// 登陆和身份验证具体实现
    /// </summary>
    public class Access
    {
        /// <summary>
        /// 默认密钥
        /// </summary>
        private const string KEY = "!@#$Q";

        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <param name="userID">用户id</param>
        /// <param name="key">密钥</param>
        /// <returns>验证码</returns>
        private static string GenCookieValStr(string userID, string key)
        {
            string source = key + "!!?" + userID + "USB";
            string valStr = Encrypt(source);
            return valStr;
        }

        /// <summary>
        /// 验证cookie
        /// </summary>
        /// <param name="cookies">传入cookie</param>
        /// <param name="key">密钥</param>
        /// <returns>是否通过验证</returns>
        public static bool CheckCookiesVal(HttpCookieCollection cookies, string key = KEY)
        {
            try
            {
                return (cookies["val"].Value == GenCookieValStr(cookies["admin_id"].Value, key));
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 设置cookie(登陆调用)
        /// </summary>
        /// <param name="cookies">传入cookie</param>
        /// <param name="userID">用户id</param>
        /// <param name="key">密钥</param>
        public static void SetCookies(HttpCookieCollection cookies, string userID, string key = KEY)
        {
            HttpCookie cookie = new HttpCookie("admin_id", userID);
            cookie.Expires = DateTime.Now.AddDays(1);
            cookies.Add(cookie);

            cookie = new HttpCookie("val", GenCookieValStr(userID, key));
            cookie.Expires = DateTime.Now.AddDays(1);
            cookies.Add(cookie);
        }

        /// <summary>
        /// MD5编码
        /// </summary>
        /// <param name="strPwd">待编码字串</param>
        /// <returns>编码结果</returns>
        static public string Encrypt(string strPwd)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] data = System.Text.Encoding.UTF8.GetBytes(strPwd);//将字符编码为一个字节序列 
            byte[] md5data = md5.ComputeHash(data);//计算data字节数组的哈希值 
            md5.Clear();
            //输出为字符串
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < md5data.Length; i++)
            {
                sb.Append(md5data[i].ToString("x").PadLeft(2, '0'));
            }
            return sb.ToString();
        }
    }


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值