【3】.net MVC 使用IPrincipal进行Form登录即权限验证

1.在MVC项目中添加用户类,可以根据实际项目需求添加必要属性

public class UserData
    {
        /// <summary>
        /// ID
        /// </summary>
        public int UserId { get; set; }

        /// <summary>
        /// 用户名
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// 角色ID列表
        /// </summary>
        public List<int> Roles { get; set; }
    }

2.添加类Principal实现IPrincipal接口

    public class Principal : IPrincipal
    {
        public IIdentity Identity { get; private set;}

        public UserData Account { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ticket"></param>
        /// <param name="account"></param>
        public Principal(FormsAuthenticationTicket ticket, UserData account)
        {
            if (ticket == null)
                throw new ArgumentNullException("ticket");
            if (account == null)
                throw new ArgumentNullException("UserData");

            this.Identity = new FormsIdentity(ticket);
            this.Account = account;
        }

        public bool IsInRole(string role)
        {
            if (string.IsNullOrEmpty(role))
                return true;
            if (this.Account == null || this.Account.Roles == null)
                return false;
            return role.Split(‘,‘).Any(q => Account.Roles.Contains(int.Parse(q)));
        }
    }

IPrincipal接口有对象Identity已经需要实现验证角色方法IsInRole()。在我们的实现类中添加了"用户信息(UserData)"属性Account。

构造函数中进行了初始化,第一个对象为Form验证的票据对象,下面ticket会携带用户信息一起保存进cookie中。

3.创建存储cookie和读取cookie的类

    /// <summary>
    /// 写入cookie和读取cookie
    /// </summary>
    public class HttpFormsAuthentication
    {
        //将用户信息通过ticket加密保存到cookie
        public static void SetAuthenticationCoolie(UserData account, int rememberDay = 0)
        {
            if (account == null)
                throw new ArgumentNullException("account");

            //序列化account对象
            string accountJson = JsonConvert.SerializeObject(account);
            //创建用户票据
            var ticket = new FormsAuthenticationTicket(1, account.UserName, DateTime.Now, DateTime.Now.AddDays(rememberDay), false, accountJson);
            //加密
            string encryptAccount = FormsAuthentication.Encrypt(ticket);

            //创建cookie
            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptAccount)
            {
                HttpOnly = true,
                Secure = FormsAuthentication.RequireSSL,
                Domain = FormsAuthentication.CookieDomain,
                Path = FormsAuthentication.FormsCookiePath
            };

            if (rememberDay > 0)
                cookie.Expires = DateTime.Now.AddDays(rememberDay);

            //写入Cookie
            HttpContext.Current.Response.Cookies.Remove(cookie.Name);
            HttpContext.Current.Response.Cookies.Add(cookie);
        }

        //获取cookie并解析出用户信息
        public static Principal TryParsePrincipal(HttpContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            HttpRequest request = context.Request;
            HttpCookie cookie = request.Cookies[FormsAuthentication.FormsCookieName];
            if (cookie == null || string.IsNullOrEmpty(cookie.Value))
            {
                return null;
            }
            //解密coolie值
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);

            UserData account = JsonConvert.DeserializeObject<UserData>(ticket.UserData);
            return new Principal(ticket, account);
        }

    }

存储cookie时将用户信息序列化后的字符串accountJson由ticket其携带加密后保存入cookie中,具体的accountJson被赋值给FormsAuthenticationTicket的UserData属性。

可看到解析时将ticket.UserData反序列化后得到了原始的用户信息对象,然后生成Principal对象。

解析cookie得到Principal对象的方法TryParsePrincipal,下面会在发起请求时用到,而返回的Principal对象被赋值给HttpContext.User。

4.在Global.asax中注册Application_PostAuthenticateRequest事件,保证权限验证前将cookie中的用户信息取出赋值给User

protected void Application_PostAuthenticateRequest(object sender, System.EventArgs e)
        {
            HttpContext.Current.User =
                HttpFormsAuthentication.TryParsePrincipal(HttpContext.Current);
        }

5.集成AuthorizeAttribute特性类并重写AuthorizeCore,HandleUnauthorizedRequest方法

    public class FormAuthorizeAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// 先进入此方法,此方法中会调用 AuthorizeCore 验证逻辑,验证不通过会调用 HandleUnauthorizedRequest 方法
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
        }

        /// <summary>
        /// 权限验证
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var user = httpContext.User as Principal;
            if (user != null)
                return user.IsInRole(base.Roles);
            return false;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            //验证不通过,直接跳转到相应页面,注意:如果不是哟娜那个以下跳转,则会继续执行Action方法
            filterContext.Result = new RedirectResult("~/Login/Index");
        }
    }

AuthorizeCore与HandleUnauthorizedRequest方法均是在方法OnAuthorization中调用,AuthorizeCore验证不通过才会调用HandleUnauthorizedRequest方法。

将验证代码在AuthorizeCore中实现,验证不通过的逻辑在HandleUnauthorizedRequest方法中实现。

6.添加LoginController实现登录逻辑

namespace MVCAuthorizeTest.Controllers
{
    public class LoginController : Controller
    {
        [AllowAnonymous]
        // GET: Login
        public ActionResult Index(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        [HttpPost]
        [AllowAnonymous]
        public ActionResult Index(string name, string password, bool rememberMe, string returnUrl)
        {
            var account = new UserData()
            {
                UserName = name,
                UserId = 110,
                Roles = new List<int>() { 1, 2, 3 }
            };
            HttpFormsAuthentication.SetAuthenticationCoolie(account, rememberMe ? 7 : 0);
            if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

        // POST: /Account/LogOff
        [HttpPost]
        public ActionResult LogOff()
        {
            System.Web.Security.FormsAuthentication.SignOut();
            return RedirectToAction("Index", "Home");
        }
    }
}

7.对需要验证的controller或action添加特性标签

    [FormAuthorize(Roles = "1,2")]
    public class HomeController : Controller
    {
        [FormAuthorize]
        public ActionResult Index()
        {
            return View();
        }
    }

如图

8.在添加FilterConfig中添加全局注册filter,减少每个action分别设置。如果有不需要验证的页面,添加[AllowAnonymous]特性即可

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            //全局注册filter
            filters.Add(new FormAuthorizeAttribute());
        }
    }
时间: 2024-10-22 02:20:25

【3】.net MVC 使用IPrincipal进行Form登录即权限验证的相关文章

从零开始实现asp.net MVC4框架网站的用户登录以及权限验证模块 详细教程

用户登录与权限验证是网站不可缺少的一部分功能,asp.net MVC4框架内置了用于实现该功能的类库,只需要简单搭建即可完成该功能. 下面详细介绍该功能的完成方法,尾部有实例源码下载,希望可以给刚开始接触MVC的朋友做个参考.     第一步:给VS安装MVC4框架 VS2012自带MVC4框架,其他版本可以使用独立安装包进行安装,这里就不讨论了,本例使用VS2013创建,.NET4.0+MVC4 第二步:创建MVC4网站项目         选择文件-新建-项目,按下图示例创建一个空的MVC网

ASP.NET MVC View 和 Web API 的基本权限验证

ASP.NET MVC 5.0已经发布一段时间了,适应了一段时间,准备把原来的MVC项目重构了一遍,先把基本权限验证这块记录一下. 环境:Windows 7 Professional SP1 + Microsoft Visual Studio 2013(MVC 5 + Web API 2) 修改Web.config,增加Forms验证模式,在system.web节点中增加以下配置: <authentication mode="Forms"> <forms loginU

django-个人博客登录及权限验证功能的实现

完成注册后随即开始进行登录,登录后页面显示登录者的名称 实现如下: 前端页面html,对session进行判断,有值则显示登录者的名字 ,无值则显示注册字样: 后台views函数  首先对验证码进行验证  验证成功后将前端传入的值放入form进行验证  验证成功后从数据库中取值进行验证,验证成功后将所有的信息全部写入session里面去后续会经常性的用到,最后返回主页. 在登录主页后如果想使用页面中的某种功能的话就需要对url进行权限的验证 ,不同的权限使用不同的功能, 权限验证过程中views

[Java]利用拦截器和自定义注解做登录以及权限验证

1.自定义注解 需要验证登录的注解 package com.etaofinance.wap.common; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Retention

php的api及登录的权限验证

类,库,接口(APi),函数,这些概念都是根据问题规模的大小来界定的.一个很小的问题肯定没有必要写成一个库,只需要写几句话就行了. 但是比如一个登录验证,这个功能很强大,很通用,可能前台后台都需要用到, 然后写一个商城,登录控制器,购物大厅控制器,购物车控制器,一般在购物车控制器查看商品之后,就直接回到购物大厅控制器显示商品列表,这时候就不需要走登录控制器 这个就是购物大厅控制器与购物车控制器协同工作,但是其实一般情况所有的控制器都需要继承一个BaseController,然后在BaseCont

Asp.net Mvc 身份验证、异常处理、权限验证(拦截器)实现代码

本问主要介绍asp.net的身份验证机制及asp.net MVC拦截器在项目中的运用.现在让我们来模拟一个简单的流程:用户登录>权限验证>异常处理 1.用户登录 验证用户是否登录成功步骤直接忽略,用户登录成功后怎么保存当前用户登录信息(session,cookie),本文介绍的是身份验证(其实就是基于cookie)的,下面看看代码. 引入命名空间 using System.Web.Security; Users ModelUser = new Users() { ID = 10000, Nam

Spring MVC + Shiro 实现权限验证

MAVEN的pom.xml 引入shiro(Spring MVC+mybatis 请参见上一章). <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.5</version> </dependency> <!-- http://mvnrepository.co

Spring MVC +MyBatis +MySQL 简单的登录查询 Demo 解决了mybatis异常

忙活了大半天,饭也没顾得上吃,哎许久不动手,一动手就出事,下面请看今天的重头戏,额吃个饭回来再发了! 1.整体结构 2.准备工作 数据库: --Mysql 5.6 创建数据库 wolf CREATE DATABASE wolf; 创建用户表 user create table user( id int  AUTO_INCREMENT  primary key, name varchar(25) not null, pwd varchar(20) not null, create_time dat

MVC应用程序实现会员登录功能

实现之前,我们已经把验证成功的信息存在cookie里<MVC登录前准备写好cookie>http://www.cnblogs.com/insus/p/3464105.html.现在就可以实现真正的验证与登录了. 先去数据库,写好一个登录证的存储过程[dbo].[usp_Member_LoginVerifyAndGetInfo]: 存储过程中有两个判断,用户输入一个不存在的帐号,也要提示帐号或是密码错误,为了系统安全考虑,一般不建议分别提示. 去应用程序,找到Entities目录,修改Membe