ASP.NET Forms身份认证详解(6)

<fieldset><legend>包含【用户信息】的自定义登录</legend> <form action="<%= Request.RawUrl %>" method="post"> <table> <tr><td>登录名:</td> <td><input type="text" value="Fish" /></td></tr> <tr><td>UserId:</td> <td><input type="text" value="78" /></td></tr> <tr><td>GroupId:</td> <td><input type="text" /> 1表示管理员用户 </td></tr> <tr><td>用户全名:</td> <td><input type="text" value="Fish Li" /></td></tr> </table> <input type="submit" value="登录" /> </form></fieldset>

登录处理代码:

public void CustomizeLogin() { // ----------------------------------------------------------------- // 注意:演示代码为了简单,这里不检查用户名与密码是否正确。 // ----------------------------------------------------------------- string loginName = Request.Form["loginName"]; if( string.IsNullOrEmpty(loginName) ) return; UserInfo userinfo = new UserInfo(); int.TryParse(Request.Form["UserId"], out userinfo.UserId); int.TryParse(Request.Form["GroupId"], out userinfo.GroupId); userinfo.UserName = Request.Form["UserName"]; // 登录状态100分钟内有效 MyFormsPrincipal<UserInfo>.SignIn(loginName, userinfo, 100); TryRedirect(); }

显示用户信息的页面代码:

<fieldset><legend>用户状态</legend><form action="<%= Request.RawUrl %>" method="post"> <% if( Request.IsAuthenticated ) { %> 当前用户已登录,登录名:<%= Context.User.Identity.Name.HtmlEncode() %> <br /> <% var user = Context.User as MyFormsPrincipal<UserInfo>; %> <% if( user != null ) { %> <%= user.UserData.ToString().HtmlEncode() %> <% } %> <input type="submit" value="退出" /> <% } else { %> <b>当前用户还未登录。</b> <% } %> </form></fieldset>

为了能让上面的页面代码发挥工作,必须在页面显示前重新设置HttpContext.User对象。
为此,我在Global.asax中添加了一个事件处理器:

protected void Application_AuthenticateRequest(object sender, EventArgs e) { HttpApplication app = (HttpApplication)sender; MyFormsPrincipal<UserInfo>.TrySetUserInfo(app.Context); } TrySetUserInfo的实现代码: /// <summary> /// 根据HttpContext对象设置用户标识对象 /// </summary> /// <param></param> public static void TrySetUserInfo(HttpContext context) { if( context == null ) throw new ArgumentNullException("context"); // 1. 读登录Cookie HttpCookie cookie = context.Request.Cookies[FormsAuthentication.FormsCookieName]; if( cookie == null || string.IsNullOrEmpty(cookie.Value) ) return; try { TUserData userData = null; // 2. 解密Cookie值,获取FormsAuthenticationTicket对象 FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value); if( ticket != null && string.IsNullOrEmpty(ticket.UserData) == false ) // 3. 还原用户数据 userData = (new JavaScriptSerializer()).Deserialize<TUserData>(ticket.UserData); if( ticket != null && userData != null ) // 4. 构造我们的MyFormsPrincipal实例,重新给context.User赋值。 context.User = new MyFormsPrincipal<TUserData>(ticket, userData); } catch { /* 有异常也不要抛出,防止攻击者试探。 */ } }

在多台服务器之间使用Forms身份认证

默认情况下,ASP.NET 生成随机密钥并将其存储在本地安全机构 (LSA) 中,因此,当需要在多台机器之间使用Forms身份认证时,就不能再使用随机生成密钥的方式, 需要我们手工指定,保证每台机器的密钥是一致的。

用于Forms身份认证的密钥可以在web.config的machineKey配置节中指定,我们还可以指定加密解密算法:

<machineKey decryption="Auto" [Auto | DES | 3DES | AES] decryptionKey="AutoGenerate,IsolateApps" [String] />

关于这二个属性,MSDN有如下解释:

ASP.NET Forms身份认证详解

在客户端程序中访问受限页面
这一小节送给所有对自动化测试感兴趣的朋友。

有时我们需要用代码访问某些页面,比如:希望用代码测试服务端的响应。

如果是简单的页面,或者页面允许所有客户端访问,这样不会有问题,但是,如果此时我们要访问的页面是一个受限页面,那么就必须也要像人工操作那样:先访问登录页面,提交登录数据,获取服务端生成的登录Cookie,接下来才能去访问其它的受限页面(但要带上登录Cookie)。

注意:由于登录Cookie通常是加密的,且会发生变化,因此直接在代码中硬编码指定登录Cookie会导致代码难以维护。

在前面的示例中,我已在web.config为MyInfo.aspx设置过禁止匿名访问,如果我用下面的代码去调用:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wjwsjz.html