一直听说 Forms 验证这种方式,可是一直都没有想过来研究。
咱先用一个例子来展示构建一个这样的验证的整个过程:(整个过程是“各个击破”)
首先在配置文件中修改验证方式:
<system.web> <authentication mode="Forms"> <forms loginUrl="~/Account/LogOn" timeout="2880" name="AUTH_MVCTEST" domain=".mvctest.com"/> </authentication> </system.web> <location> <system.web> <authorization> <allow users="Admin"/> <deny users="*"/> </authorization> </system.web> </location> <location path="Index"> <system.web> <authorization> <deny users="?"/> </authorization> </system.web> </location>
咱先解释下这个配置,红色 字 表示该应用程序(WEB)对用户的验证方式是基于Forms的,而后面会降到,其实际上就是添加一个Cookie来贯穿整个验证机制。
forms节点中的name表示该Cookie的名字,domain 表示域,timeout 表示 该cookie的过期时间。这些都可以在下图中看到(FF firebug)。
接下来的location节点,是对用户访问页面的授权,没有path参数的表示对所有的页面的授权,表示[允许]Admin访问,[拒绝]此外的所有用户。
第二个location,带有path参数,表示是对Index目录下的页面访问授权,这就相当于一个在Index目录下的局部变量,优先级在Index目录下是最高的。
其含义是:拒绝所有匿名用户,也就是不管谁,登录了就能访问。
注: authentication 为验证的意思,authorization 为授权的意思。
测试时不要忘了把“域”改过来,否则cookie不在当前域中,肯定是测试不通过的。
如果不设置 域 ,那么将会是顶级域,在子域将失效。
下图为不设置域时的默认值:
这样如果你有二级站点,cookie就没用了。
----------------------------------------------------------------------------------------------------------------------------------------
下面粘贴后台代码:(C# MVC3.0)
/Account/LogOn
public ActionResult LogOn(LogonModel model, string ReturnUrl) { if (model.Name == "Admin" && model.PassWord == "111111") { FormsAuthentication.SetAuthCookie(model.Name, true); return RedirectToAction("Index","Index"); } return View(); }
Logon.cshtml
<div> @using (Html.BeginForm()) { <text>用户名:</text> <input name="Name" type="text" value="" /> <text>密码:</text> <input type="password" name="PassWord" /> <input type="submit" value="登录" /> } </div>
/Index/Index
public ActionResult Index() { if (User.Identity.IsAuthenticated) { ViewData["msg"] = "通过验证的页面"; return View(); } else { return RedirectToAction("LogOn", "Account"); } }
Index.cshtml
<div> @ViewData["msg"] </div>
上面大致是这样一个过程,判断用户名密码是否正确,如果正确,则添加用于验证授权的Cookie,并跳转到/Index/Index页面,在该页面判断是否验证成功
(Request.IsAuthenticated或者 User.Identity.IsAuthenticated),成功则显示页面,否则跳转到登录页面。
但是这个Cookie到底是怎么生成的?它是怎么根据配置文件中的 users 来授权的?
最近我喜欢通过类库来说明些问题:让我们来看看cookie是从哪儿跳出来的:(.net reflector 6 -- 软件自行下载)
【图 1】 SetAuthCookie
【图 2】 GetAuthCookie
【图 3】 FromUtc
查看代码,查找 SetAuthCookie,如 上【图1】所示,Cookie 原来来自GetAuthCookie(如【图2】),从返回值一直追溯到来源,该Cookie内容来自于 验证凭票 的加密串。可是FromUtc(如【图3】)是什么东西? 跳过去看下,原来就是对 验证凭票 的一个实例化而已。至于怎么加密的,我就不跳过去看了。
好了,这就是所谓的Forms验证的东西。内容比较浅显,不当之处,请批评指正。(备注也重要哦)
备注:1、如果你发现代码中有ReturnUrl我没有用到。在你访问页面A时,你没登录,然后跳转到登录页 ReturnUrl 就是这个A页面。登录成功后会自动跳转到A页面。
也可以改成:
return Redirect(ReturnUrl);
2、加密过的验证凭票也是可以解出来的哦:
DateTime dt = ((FormsIdentity)User.Identity).Ticket.Expiration;
这里获得的是 验证凭票 的过期时间。默认情况下,这个过期时间跟基于它生成的Cookie的过期时间是一样的。
3、可能大家在很多网上登录时可以看到诸如:“10天之内自动登录”、“记住我” 的选项
我刚想到一个解决办法:三个cookie,
第一个则为刚才生成的 授权Cookie,
第二个是记住用户名要用的Cookie,这个Cookie过期时间设置100年吧。
第三个是是否自动登录。
有人就问了,那“10”天登录哪儿去了,在配置文件里面 timeout 设置为 14400 (单位是分钟)。
有人又问了,第三个Cookie似乎没用啊,按照上述的设置,能够保证用户10天内自动登录呢。可是万一我不想每次访问都自动登录呢?就需要这第三个Cookie了。
有可能有些朋友在使用SetAuthCookie的时候把第二个参数设置成false了。
而第二个参数有啥用呢?
这个布尔值用处可大了。如果设置为false,那么上述生成的Cookie就是会话Cookie。浏览器一关,Cookie就清除了。
只有设置成true,配置文件中的timeout才会生效。
4、当然登录后的用户可以通过 User.Identity.Name 来获取了。
AuthenticationType 在这里的值 为 Forms.
结束:鉴于对config结构不清楚的,这里附一张图,可供参考!
最最后,补充一点: 如果希望不同的子站点共享Forms的验证,务必注意两点:
1、domain的设置
2、各子站点,必须使用同一个IIS应用程序池