首页 > 代码库 > MVC 登录认证与授权
MVC 登录认证与授权
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来。
十年河东十年河西,莫欺少年穷
学无止境,精益求精
最近在做自学MVC,遇到的问题很多,索性一点点总结下。
正题:
做过三层架构的童鞋都知道,如果要验证/授权一个用户登录,我们一般采取如下方法:
1、用户输入用户名、密码进行登录
2、账户/密码正确,保存用户信息至Cookies或者Session,跳转至主页面
3、在主页面Page_Load的时候,判断Cookies或者Session的值,如果Cookies或者Session中存放的值在数据库验证成功,则可以观看主页面信息,如果验证不成功,或者Session/Cookies值为NULL时,直接执行语句:Response.Redirect(../Login.aspx);
上述方法很简单,功能上也实现了登录的认证与授权,相信很多人写的项目都会采取此方法进行判断,殊不知:这种方法安全系数较低,而且违背了NET的登录授权与验证原则。那么NET中的授权与验证又是什么呢?
.net中的认证(authentication)与授权(authorization)
认证(authentication) 就是 :判断用户有没有登录,用户输入的账户密码等信息是否通过数据库比对
授权(authorization) 就是:用户登录后的身份/角色识别,用户通过认证后<登陆后>我们记录用户的信息并授权
.net中与"认证"对应的是IIdentity接口,而与"授权"对应的则是IPrincipal接口,这二个接口的定义均在命名空间System.Security.Principal中,详情如下:
用户认证接口:
using System; using System.Runtime.InteropServices; namespace System.Security.Principal { [ComVisible(true)] public interface IIdentity { string AuthenticationType { get; } bool IsAuthenticated { get; } string Name { get; } } }
用户授权接口:
using System; using System.Runtime.InteropServices; namespace System.Security.Principal { [ComVisible(true)] public interface IPrincipal { IIdentity Identity { get; } bool IsInRole(string role); } }
应该注意到:IPrincipal接口中包含着一个只读的IIdentity
1、IIdentity 接口中属性的含义:
AuthenticationType 验证方式:NET中有Windows、Forms、Passport三种验证方式,其中以Forms验证用的最多,本节讲解的MVC验证与授权就是基于Form。
IsAuthenticated 是否通过验证,布尔值
Name 用户登录的账户名称
2、IPrincipal 接口中属性的含义:
IIdentity 上述IIdentity接口的实例
IsInRole 布尔值,验证用户权限
下面我们对HttpContext.Current.User刨根问底
HttpContext.User本身就是一个IPrincipal接口的实例。
有了上面的预备知识,我们在程序中处理认证问题时,只需对HttpContext.User赋值即可。
下面是小弟模拟的一个授权方法
/// <summary> /// 模拟授权 此处不经过验证 直接授权访问 UserCenter() /// </summary> /// <returns></returns> public ActionResult Login() { GenericIdentity _identity = new GenericIdentity("天才卧龙", "Forms"); GenericPrincipal _principal = new GenericPrincipal(_identity, new string[] { "admins", "vips" }); HttpContext.User = _principal; return RedirectToAction("UserCenter"); } [Authorize(Roles = "admins")] public ActionResult UserCenter() { return View(); }
上面的方法中,一旦运行登陆页,不需要填账户密码,直接会访问UserCenter(),即:直接会跳转到个人中心
好啦,如果上边的例子大家看懂了,那么下面的登录其实就很简单了,和上述所讲一样:由于 HttpContext.User 本身就是一个IPrincipal接口的实例!因此:我们只需给这个实例赋值即可,上面的例子就证实了这一点。
咱们回到开篇的描述,一般我们都是通过Session或者cookies就行Forms验证登录,那么在MVC中我们应当怎么做呢?
1.MVC使用Forms验证存储用户自定义信息
Forms验证在内部的机制为把用户数据加密后保存在一个基于cookie的票据FormsAuthenticationTicket中,因为是经过特殊加密的,所以应该来说是比较安全的。而.net除了用这个票据存放自己的信息外,还留了一个地给用户自由支配,这就是现在要说的UserData。
UserData可以用来存储string类型的信息,并且也享受Forms验证提供的加密保护,当我们需要这些信息时,也可以通过简单的get方法得到,兼顾了安全性和易用性,用来保存一些必须的敏感信息还是很有用的。
2、FormsAuthenticationTicket基于forms的验证
构建基于forms的验证机制过程如下:
1,设置IIS为可匿名访问和asp.net web.config中设置为form验证,配置webConfig,如下:
<!--用户没有授权时 自动退回登陆界面--> <authentication mode="Forms"> <forms loginUrl="~/Home/Login" timeout="2880" path="/" /> </authentication>
2,检索数据存储验证用户,并检索角色(其实就是登录验证)
3,使用FormsAuthenticationTicket创建一个Cookie并回发到客户端,并存储
关于2、3两步,我以代码示例:
我创建的登录Model如下:
public class UserLogin { private readonly object LOCK = new object(); Maticsoft.BLL.YX_UserInfo Bll = new Maticsoft.BLL.YX_UserInfo(); Maticsoft.Model.YX_UserInfo Mol = new Maticsoft.Model.YX_UserInfo(); // [Required(ErrorMessage = "请输入账户号码/手机号")] [RegularExpression(@"^1[3458][0-9]{9}$", ErrorMessage = "手机号格式不正确")] public string UserName { get; set; } [Required(ErrorMessage="请输入账户密码")] [DataType(DataType.Password,ErrorMessage="密码格式不正确")] [MinLength(6, ErrorMessage = "密码长度介于6~15位之间")] [MaxLength(15, ErrorMessage = "密码长度介于6~15位之间")] public string UserPwd { get; set; } public bool LoginAction() { lock (LOCK) { DataTable dt = Bll.GetList(" Uname=‘" + CommonMethod.CheckParamThrow(UserName) + "‘ and Upwd=‘" + CommonMethod.Md532(UserPwd) + "‘ and flat1=1").Tables[0]; if (dt.Rows.Count > 0) { FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, UserName, DateTime.Now, DateTime.Now.AddMinutes(30), false, "admins,vip", "/" ); string encryptedTicket = FormsAuthentication.Encrypt(authTicket); System.Web.HttpCookie authCookie = new System.Web.HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); System.Web.HttpContext.Current.Response.Cookies.Add(authCookie); return true; } else { return false; } } } }
上述代码中
数据库验证成功,我们将用户信息存入Cookies,
然后我们在Global中解析这个Cookies,然后把解析的结果赋值给:HttpContext.User
代码如下:
/// <summary> /// 登录验证、s授权 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Application_AuthenticateRequest(Object sender, EventArgs e) { string cookieName = FormsAuthentication.FormsCookieName; HttpCookie authCookie = Context.Request.Cookies[cookieName]; FormsAuthenticationTicket authTicket = null; try { authTicket = FormsAuthentication.Decrypt(authCookie.Value); } catch (Exception ex) { return; } string[] roles = authTicket.UserData.Split(‘,‘); FormsIdentity id = new FormsIdentity(authTicket); GenericPrincipal principal = new GenericPrincipal(id, roles); Context.User = principal;//存到HttpContext.User中 }
Context.User一旦被赋值成功,我们就可以访问那些有权限限制的方法。代码如下:
[Authorize(Roles = "admins")] public ActionResult UserCenter() { return View(); }
SO,搞懂了本质,一切都可以解决
讲完了,再见--今天请求我郑州的女友帮我解答,一直没能联系到她人,索性自己琢磨。
@陈卧龙的博客
MVC 登录认证与授权