MVC身份验证及权限管理(转载)

from https://www.cnblogs.com/asks/p/4372783.html

MVC自带的ActionFilter

在Asp.Net WebForm的中要做到身份认证微软为我们提供了三种方式,其中最常用的就是我们的Form认证,需要配置相应的信息。例如下面的配置信息:

复制代码
<authentication mode="Forms"><forms loginUrl="Login.aspx" defaultUrl="Default.aspx" protection="All" />
</authentication>
<authorization><deny users="?"/><allow users="*"/>
</authorization>
复制代码

说明我们登录页面是Login.aspx,登录成功后的默认页面是Default.aspx,而我们用户信息采用验证和加密两种方式。而且最重要的 是我们要写好授权方式(下面的授权一定要写否则只说明使用Forms认证然后设置相关属性是没有用的),拒绝所有匿名用户,只有登录用户可以正常访问。这 样之后我们设置点击登录按钮将用户名写进cookie(也就是执行FormsAuthentication.SetAuthCookie(name, false);)就可以了。

在Asp.Net MVC中我们同样可以使用Forms认证,但是如果你按照WebForm中的做法去做就不行了。例如你这样配置信息:

复制代码
<authentication mode="Forms"><forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All"/>
</authentication>
<authorization><deny users="?"/><allow users="*"/>
</authorization>
复制代码

你在Login.aspx中设置登录来触发AccountController中的Logon来登录,其中Logon代码:

复制代码
public ActionResult Logon(string name,string password)    
{    if (name == "jianxin160" && password == "160796")    {    FormsAuthentication.SetAuthCookie(name, false);    return Redirect("~/Home/Index");    }    else{    return Redirect("/");    }    
}
复制代码

这样的操作之后你会发现你的Logon是不会执行的。原因是什么呢?怎么同样的设置为什么到了MVC中就不行了?原因就是二者机制不同,因为你设置的授权方式让Logon无法访问了。那么我们怎么来做呢?

其实在Asp.Net MVC中我们有更好的方式来做这一切,我们不需要授权方式,也就是说我们的配置信息像这样:

<authentication mode="Forms"><forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All"/>
</authentication>

不需要说明匿名用户不能登录等。当然了,你会发现仅仅就这样做肯定不行的我们还要换一种方式告诉系统哪些是需要登录才能访问的。你或许 想,o(︶︿︶)o 唉,那太麻烦了吧。其实不是这样的,很简单,我们只需要在需要认证的Action上标记[Authorize]就可以了。例如我在Home文件夹中有两个 页面Index和Home,我现在想让Index经过认证才能访问,而Home不需要,那么只需要给Index这个Action标记 [Authorize],也就是:

复制代码
[Authorize]    
public ActionResult Index()    
{    return View();    
}    public ActionResult Home()    
{    return View();    
}
复制代码

这样Index就必须登录之后才能访问,而Home是不需要登录的。如果你需要进行角色授权那么您就可以在标记Authorize的时候指明角色 (例如[Authorize(Role=Administrators)] ),不过您这是就必须使用微软给我们提供的Membership机制了,因为您的Role不可能是平白无故有的,而是存在于对应的数据库中的,这个我在另 一篇博客中提到过就不多说了。

自定义ActionFilter

有时候这样的认证或许您还不能够满足,或者说您觉得不够灵活,那么也没有关系,Asp.Net MVC是允许您自定义ActionFilter的。例如我现在自定义身份认证:

复制代码
using System;   
using System.Collections.Generic;   
using System.Linq;   
using System.Web;   
using System.Web.Mvc;   
using System.Web.Security;    namespace FormFormsAuthenticationMvc   
{   public class RequiresAuthenticationAttribute:ActionFilterAttribute   {   public override void  OnActionExecuting(ActionExecutingContext filterContext)   {   if (!filterContext.HttpContext.User.Identity.IsAuthenticated)   {   string returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath;   string redirectUrl = string.Format("?ReturnUrl={0}", returnUrl);   string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;   filterContext.HttpContext.Response.Redirect(loginUrl, true);   }   }    }   
}
复制代码

如果需要进行用户管理,我再定义角色相关的Filter:

复制代码
using System;    
using System.Collections.Generic;    
using System.Linq;    
using System.Web;    
using System.Web.Mvc;    
using System.Web.Security;    namespace MvcApplication1.MyClass    
{    public class RequiresRoleAttribute:ActionFilterAttribute    {    public string Role { get; set; }    public override void OnActionExecuting(ActionExecutingContext filterContext)    {    if (!string.IsNullOrEmpty(Role))    {    if (!filterContext.HttpContext.User.Identity.IsAuthenticated)    {    string returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath;    string redirectUrl = string.Format("?ReturnUrl={0}", returnUrl);    string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;    filterContext.HttpContext.Response.Redirect(loginUrl, true);    }    else{    bool isAuthenticated = filterContext.HttpContext.User.IsInRole(Role);    if (!isAuthenticated)    {    throw new UnauthorizedAccessException("You have no right to view the page!");    }    }    }    else{    throw new InvalidOperationException("No Role Specified!");    }    }    }    
}
复制代码

其实您会发现上面两个Attribute其实MVC自带的Authorized已经解决了,这里主要告诉大家如果有需要您是可以扩展的。

好了,今天就到这里吧!源代码下载:FormFormsAuthenticationMvc

 

ASP.NET MVC 建立 ASP.NET 基础之上,很多 ASP.NET 的特性(如窗体身份验证、成员资格)在 MVC 中可以直接使用。本文旨在提供可参考的代码,不会涉及这方面太多理论的知识。

本文仅使用 ASP.NET 的窗体身份验证,不会使用它的 成员资格(Membership) 和 角色管理 (RoleManager),原因有二:一是不灵活,二是和 MVC 关系不太。

一、示例项目

image

User.cs 是模型文件,其中包含了 User 类:

复制代码
public class User
{public int ID { get; set; }public string Name { get; set; }public string Password { get; set; }public string[] Roles { get; set;  }
}
复制代码

UserRepository 为数据存取类,为了演示方便,并没有连接数据库,而是使用一个数组来作为数据源:

复制代码
public class UserRepository
{private static User[] usersForTest = new[]{new User{ ID = 1, Name = "bob", Password = "bob", Roles = new []{"employee"}},new User{ ID = 2, Name = "tom", Password = "tom", Roles = new []{"manager"}},new User{ ID = 3, Name = "admin", Password = "admin", Roles = new[]{"admin"}},};public bool ValidateUser(string userName, string password){return usersForTest.Any(u => u.Name == userName && u.Password == password);}public string[] GetRoles(string userName){return usersForTest.Where(u => u.Name == userName).Select(u => u.Roles).FirstOrDefault();}public User GetByNameAndPassword(string name, string password){return usersForTest.FirstOrDefault(u => u.Name == name && u.Password == password);}
}
复制代码

二、用户登录及身份验证

方式一

修改 AccountController:原有 AccountController 为了实现控制反转,对窗体身份验证进行了抽象。为了演示方便,我去除了这部分(以及注册及修改密码部分):

复制代码
public class AccountController : Controller
{private UserRepository repository = new UserRepository();public ActionResult LogOn(){return View();}[HttpPost]public ActionResult LogOn(LogOnModel model, string returnUrl){if (ModelState.IsValid){if (repository.ValidateUser(model.UserName, model.Password)){FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl);else return RedirectToAction("Index", "Home");}elseModelState.AddModelError("", "用户名或密码不正确!");}return View(model);}public ActionResult LogOff(){FormsAuthentication.SignOut();return RedirectToAction("Index", "Home");}
}
复制代码

修改 Global.asax:

复制代码
public class MvcApplication : System.Web.HttpApplication
{public MvcApplication(){AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);}void MvcApplication_AuthorizeRequest(object sender, EventArgs e){IIdentity id = Context.User.Identity;if (id.IsAuthenticated){var roles = new UserRepository().GetRoles(id.Name);Context.User = new GenericPrincipal(id, roles);}}//...
}
复制代码

给 MvcApplication 增加构造函数,在其中增加 AuthorizeRequest 事件的处理函数。

代码下载:Mvc-FormsAuthentication-RolesAuthorization-1.rar (243KB)

方式二

此方式将用户的角色保存至用户 Cookie,使用到了 FormsAuthenticationTicket。

修改 AccountController:

复制代码
public class AccountController : Controller
{private UserRepository repository = new UserRepository();public ActionResult LogOn(){return View();}[HttpPost]public ActionResult LogOn(LogOnModel model, string returnUrl){if (ModelState.IsValid){User user = repository.GetByNameAndPassword(model.UserName, model.Password);if (user != null){FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,user.Name,DateTime.Now,DateTime.Now.Add(FormsAuthentication.Timeout),model.RememberMe,user.Roles.Aggregate((i,j)=>i+","+j));                    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,FormsAuthentication.Encrypt(ticket));Response.Cookies.Add(cookie);if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl);else return RedirectToAction("Index", "Home");}elseModelState.AddModelError("", "用户名或密码不正确!");}return View(model);}public ActionResult LogOff(){FormsAuthentication.SignOut();return RedirectToAction("Index", "Home");}
}
复制代码

修改 Global.asax:

复制代码
public class MvcApplication : System.Web.HttpApplication
{public MvcApplication(){AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);}void MvcApplication_AuthorizeRequest(object sender, EventArgs e){var id = Context.User.Identity as FormsIdentity;if (id != null && id.IsAuthenticated){var roles = id.Ticket.UserData.Split(',');Context.User = new GenericPrincipal(id, roles);}}//...
}
复制代码

代码下载:Mvc-FormsAuthentication-RolesAuthorization-2.rar (244KB)

三、角色权限

使用任一种方式后,我们就可以在 Controller 中使用 AuthorizeAttribute 实现基于角色的权限管理了:

复制代码
[Authorize(Roles = "employee,manager")]
public ActionResult Index1()
{return View();
}
[Authorize(Roles = "manager")]
public ActionResult Index2()
{return View();
}
[Authorize(Users="admin", Roles = "admin")]
public ActionResult Index3()
{return View();
}
复制代码

四、简要说明

MVC 使用 HttpContext.User 属性进行来进行实现身份验证及角色管理,同样 AuthorizeAttribute 也根据 HttpContext.User 进行角色权限验证。

因些不要在用户登录后,将相关用户信息保存在 Session 中(网上经常看到这种做法),将用户保存在 Session 中是一种非常不好的做法。

也不要在 Action 中进行角色权限判断,应该使用 AuthorizeAttribute 或它的子类,以下的方式都是错误的:

复制代码
public ActionResult Action1()
{if (Session["User"] == null) { /**/}/**/
}
public ActionResult Action2()
{if (User.Identity == null) { /**/}if (User.Identity.IsAuthenticated == false) { /**/}if (User.IsInRole("admin") == false) { /**/}/**/
}
复制代码

转载于:https://www.cnblogs.com/huangzelin/p/10613301.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/279808.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF-23 基于Timer任务调度

.NET的FCL中提供了几个计时器&#xff0c;大多数初学者都不清楚他们有什么不同&#xff0c;那我们这节来剖解一下每个计时器的本质&#xff1a;1.System.Threading.Timer如果在一个线程池上执行一个定时的周期性的后台线程任务他是最好的选择&#xff0c;这个类是和线程池相关联…

在.NET中不安装Office使用EPPlus生成带图表(Chart)的Excel报表

在开发.NET应用中可能会遇到需要生成带图表(Chart)的Excel报表的需求&#xff0c;特别是在一些ASP.NET网站中&#xff0c;有时候我们并不能保证Web服务器上一定安装了Office组件&#xff0c;所以使用微软的Office来生成Excel并不保证在所有情况下都使用&#xff0c;有时候即使W…

facebook 邀请好友_如何在Facebook上与某人解除好友

facebook 邀请好友It’s very easy for your Facebook News Feed to get cluttered. After a few years adding ukulele playing magicians you meet wandering the street and the bar staff at every bar you go to regularly, it gets overrun with people you’ll never se…

mac下npm/node的安装和卸载、升级;node、npm升级后最后删掉node_modules重新安装

mac还是使用brew install简单一些&#xff1b;最好使用一种安装方式&#xff0c;不要多种方式互用&#xff1b; 更新npm到最新版本npm install -g npm更新npm到指定版本 npm -g install npm2.9.1指定安装目录npm install --prefix /usr/local -g npm 1、从官网https://nodejs.o…

Edison的2022年终总结

大家好&#xff0c;我是Edison。2022年即将结束&#xff0c;又到了做年终总结的时候&#xff0c;它是我每年的一个习惯&#xff0c;意味着又要开始新的征途&#xff0c;在开始新的征途之前回顾一下很有必要。艰难抉择&#xff1a;从互联网到制造业今年最大的变化就是又换了份工…

JNI

配置NDK&#xff0c;调用JNI最终会生成一个so库&#xff0c;如果so库生成了。直接在项目中使用so库即可调用本地方法。注意&#xff1a;api的包名要与so库定义的包名一致。 1什么是jni jni java native interface java本地开发接口&#xff0c;是JAVA和C互相调用的桥梁。 2jni有…

dvd vlc 复制_如何使用VLC翻录DVD

dvd vlc 复制There are many ways to rip a DVD to your computer, but if you’re looking for the most straightforward option, VLC is easy and free. Besides, you probably already have VLC on your computer (and if you don’t, you should). Here, we’ll show you …

新年芯事 | 龙芯物联网主控芯片龙芯1C102和龙芯1C103流片成功

前言近期&#xff0c;龙芯中科面向物联网领域研制的主控芯片--龙芯1C102和龙芯1C103流片成功&#xff0c;两款微控制器芯片各项功能测试正常&#xff0c;符合设计预期。 龙芯1C102主要面向智能家居以及其他物联网设备详细介绍龙芯1C102采用龙芯LA132处理器核心&#xff0c;是一…

【加更】搭建基于chatgpt的钉钉聊天机器人

应某些小伙伴的加更请求&#xff0c;出一期基于钉钉上的聊天机器人&#xff0c;我顺便加更一期&#xff0c;搭建一个钉钉聊天机器人的小教程。首先进入到钉钉开放平台的后台管理系统&#xff1a;https://open.dingtalk.com/进入到 应用开发->企业内部开发->机器人右上角选…

word中 有注释标签吗_如何在Word中注释图像

word中 有注释标签吗If you’re writing a document that includes images, you may want to add annotations to those images to clarify what they represent. You can add callouts to your images to point out particular parts of the image and add text to describe t…

牛客网暑期ACM多校训练营(第二场)J farm (二维树状数组)

题目链接&#xff1a; https://www.nowcoder.com/acm/contest/140/J 思路&#xff1a; 都写在代码注释里了&#xff0c;非常好懂。。 for_each函数可以去看一下&#xff0c;遍历起vector数组比较方便&#xff0c;用for(int i 0;i < q[i].size();i)的话&#xff0c;是会有一…

微软IE 9 Beta全程体验图集

微软刚刚更新了IE 9 Beta的新页面&#xff0c;此次发布的Beta版本一共有27个国家的语言&#xff0c;其中也包括了简体中文和香港和台湾的繁体中文版。 点击此处进入下载页面&#xff1a; http://windows.microsoft.com/zh-CN/internet-explorer/download/ie-9/worldwide IE9的热…

.net core中Quartz的使用方法

我们在日常开发中&#xff0c;总会遇到这样的需求&#xff1a;每隔一段时间&#xff0c;执行一次某个任务。固定某个时间执行任务&#xff0c;例如凌晨12点对当天的数据进行统计。每个月的第几天&#xff0c;执行某个任务。Quartz.Net是根据Java的Quartz用C#改写而来&#xff0…

windows10访客_如何在Windows 10中创建访客帐户

windows10访客If you find that your guests are asking fairly often to use your computer temporarily to check their email or look something up on the web, you don’t have to let them use your personal account or create a special account for each guest. 如果发…

几个有趣的算法题目

本文首发 http://svtter.cn最接近的数字 题目 一个K位的数N $$ (K\leq2000&#xff0c;N\leq10^{20}) $$ 找出一个比N大且最接近的数&#xff0c;这个数的每位之和与N相同&#xff0c;用代码实现之。 例如&#xff1a;0050 所求书数字为0104&#xff1b;112 所求数为121&#x…

获取一篇新闻的全部信息

给定一篇新闻的链接newsUrl&#xff0c;获取该新闻的全部信息 标题、作者、发布单位、审核、来源 发布时间:转换成datetime类型 点击&#xff1a; newsUrlnewsId(使用正则表达式re)clickUrl(str.format(newsId))requests.get(clickUrl)newClick(用字符串处理&#xff0c;或正则…

上twitter_如何在Twitter上更改您的显示名称

上twitterUnlike Facebook, Twitter has never insisted people user their real names. In fact, there’s a long tradition of people changing their names to a joke or pun because it’s Christmas or Halloween, or just for no reason at all. 与Facebook不同&#xf…

网桥

配置实现网桥 网桥&#xff1a;即桥接 把一套机器上的若干个网络接口 “连接” 起来&#xff0c;其结果是&#xff0c;其中一个网口收到的报文会被复制给其他网口并发送出去。以使得网口之间的报文能够互相转发。网桥就是这样一个设备&#xff0c;它有若干个网口&#xff0c;并…

raspberry pi_在月光下将Raspberry Pi变成蒸汽机

raspberry piValve’s Steam Machines aim to bring your Steam game library right into your living room (but at a rather steep premium). Today we’ll show you how to bring your Steam library (plus all your other computer games) to your living room for a fract…

MySql数据库出现 1396错误

1、安装MySql数据库后。创建新的用户。有可能会出现 1396这个错误&#xff0c; 2、解决的办法如下&#xff1a;假装有你需要创建的这个用户、先删了。再创建。 3、这样就可以解决用户创建不成功的问题了。 转载于:https://www.cnblogs.com/chifa/p/9362882.html