安全性是 ASP.NET Web 应用程序中一个非常重要的方面。它涉及内容非常广泛,不能在一篇文章内说明所有的安全规范,本文讲述如何利用Forms 身份验证构建安全的 ASP.NET 应用程序,它是目前被使用最多最广的验证/授权方式。
本文以ASP.NET2.0在Forms 身份验证上的实现方法进行说明。相信读者都己经看过许多类似这样的文章,无论是在网上或是某些专业书籍上。最近又出现了非常多的以WCF或者ASP.NET MVC关于安全模型指南,可见构建网站安全总是不过时的话题。
本文旨在以简单的方法一步一步讲述网站的安全认证框架,以起到抛砖引玉的作用。相信你在看完本文时,一定会有所收获。
首先,需要配置根目录下的web.config文件:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <authentication mode="Forms"> <forms name="SunnyWay" protection="All" timeout="30" loginUrl="~/Login.aspx" defaultUrl="~/" slidingExpiration="true"/> </authentication> </system.web> </configuration> |
< authentication>元素的mode属性指定应用程序的默认身份验证模式(默认值为 Windows)。此属性可以为下列值之一:
Windows |
将 Windows 验证指定为默认的身份验证模式。将它与以下任意形式的 Microsoft Internet 信息服务 (IIS) 身份验证结合起来使用:基本、摘要、集成 Windows 身份验证 (NTLM/Kerberos) 或证书。在这种情况下,您的应用程序将身份验证责任委托给基础 IIS。 |
Forms |
将 ASP.NET 基于窗体的身份验证指定为默认身份验证模式。 |
Passport |
将 Microsoft Passport Network 身份验证指定为默认身份验证模式。 |
None |
不指定任何身份验证。您的应用程序仅期待匿名用户,否则它将提供自己的身份验证。 |
下面是本示例使用的< forms>元素的属性,更多信息请参阅MSDN:
name |
指定要用于身份验证的 HTTP Cookie。如果正在一台服务器上运行多个应用程序并且每个应用程序都需要唯一的 Cookie,则必须在每个应用程序的 Web.config 文件中配置 Cookie 名称。 默认值为 ".ASPXAUTH"。 |
protection |
指定应用程序同时使用数据验证和加密方法来保护 Cookie。该选项使用已配置的数据验证算法,该算法基于 machineKey 元素。如果三重 DES (3DES) 可用并且密钥足够长(48 位或更长),则使用三重 DES 进行加密。默认值(建议值)为 All。其他可选值(Encryption、None、Validation)信息请参阅MSDN |
timeout |
指定 Cookie 过期前逝去的时间(以整数分钟为单位)。如果 SlidingExpiration 属性为 true,则 timeout 属性是滑动值,会在接收到上一个请求之后的指定时间(以分钟为单位)后过期。为防止危及性能并避免向开启 Cookie 警告的用户发出多个浏览器警告,当指定的时间逝去大半时将更新 Cookie。这可能导致精确性受损。默认值为 "30"(30 分钟)。 |
loginUrl |
指定如果找不到任何有效的身份验证 Cookie,将请求重定向到的用于登录的 URL。默认值为 login.aspx。 |
defaultUrl |
定义在身份验证之后用于重定向的默认 URL。此属性是 .NET Framework 2.0 版中的新属性。默认值为 "default.aspx"。 |
slidingExpiration |
指定是否启用可调过期时间。可调过期将 Cookie 的当前身份验证时间重置为在单个会话期间收到每个请求时过期。默认值为true。 |
下面在项目中创建一个文件夹Member,先在此文件夹下创建一个web.config文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings/> <connectionStrings/> <system.web> <authorization> </authorization> </system.web> </configuration> |
假设访问此文件夹下的所有资源时,都需要通过权限认证。此时,认证分为两种情况:
1. 只要是登录用户即可访问。
2. 必须是特定用户组的成员才可访问。
在第一种情况下,需要做出以下配置:
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings/> <connectionStrings/> <system.web> <authorization> <deny users="?"/> <allow users="*"/> </authorization> </system.web> </configuration> |
此配置意为,先通过所有用户的请求,再拒绝匿名用户的请求。那么在此时访问/Member/Default.aspx时,请求将被拒绝,继而转向在根目录下的web.config文件中,<forms>节点的loginUrl属性所配置的页面(在本例中,是Login.aspx)。
在Login.aspx中,将执行用户登录的操作。如果用户登录成功,你可以使用以下代码进行跳转:
FormsAuthentication.RedirectFromLoginPage("成功登录的用户的用户名", false); |
此时,将会跳转到之前访问的页面去。如果是直接访问的Login.aspx,页面将会跳转到<forms>节点的defaultUrl属性所配置的页面。
在第二种情况下,并不是已登录用户就可以访问的,必须是特定用户组的成员才可访问,例如Administrators、Users等。此时需要在/Member/web.config中做出的配置如下:
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings/> <connectionStrings/> <system.web> <authorization> <allow roles="Administrators,Users"/> <deny users="*"/> </authorization> </system.web> </configuration> |
此配置意为,先拒绝所有用户的请求,再通过属于Administrators,Users用户组的成员的请求。那么在此时访问/Member/Default.aspx时,不仅需要登录,而且登录用户还要属于Administrators或者Users用户组,否则请求将被拒绝,继而转向登录页。此时,在登录页中执行的操作如下:
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket ( 0 , "张三" , DateTime.Now , chkRemember.Checked ? DateTime.Now.AddYears(1) : DateTime.Now.AddMinutes(30) , chkRemember.Checked ? true : false , "Administrators,Users" ); string encryptedTicket = FormsAuthentication.Encrypt(authTicket); //加密 HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); Response.Cookies.Add(authCookie); if (String.IsNullOrEmpty(Request.QueryString["ReturnUrl"])) { Response.Redirect(FormsAuthentication.DefaultUrl); } else { Response.Redirect(Request.QueryString["ReturnUrl"]); } |
FormsAuthenticationTicket的类说明:提供对票证的属性和值的访问,这些票证用于 Forms 身份验证对用户进行标识。
本示例所采用的构造函数各参数说明如下:
int version, 票证的版本号。 string name, 与票证关联的用户名。 DateTime issueDate, 票证发出时的本地日期和时间。 DateTime expiration,票证过期时的本地日期和时间。 bool isPersistent, 如果票证将存储在持久性 Cookie 中(跨浏览器会话保存),则为 true;否则为 false。如果该票证存储在 URL 中,将忽略此值。 string userData, 存储在票证中的用户特定的数据。 |
此时,已经将加密后的信息存入了Cookie中,还需要在网站根目录下创建Global.asax文件,在文件中加入Application_AuthenticateRequest事件,该事件将在安全模块建立起当前用户的有效的身份时被触发。事件代码如下:
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(new char[] { ',' });//如果存取多个角色,我们把它分解 FormsIdentity id = new FormsIdentity(authTicket); System.Security.Principal.GenericPrincipal principal = new System.Security.Principal.GenericPrincipal(id, roles); Context.User = principal;//存到HttpContext.User中 } |
在Application_AuthenticateRequest事件中,对Cookie进行解密,并赋值给Context.User对象。然后,页面将会请求访问/Member/Default.aspx,这时将调用Context.User对象的IsInRole方法,如果返回true,则显示页面内容,如果返回false,则转向登录页。
最后,对Context.User对象进行简单说明。Context.User是一个IPrincipal接口成员,它有一个方法和一个属性:
IsInRole(string roleName) |
确定当前用户是否属于指定的角色。 |
Identity属性 |
获取当前用户的标识。 |
方法IsInRole就是在配置文件中指定了<allow roles="Administrators,Users"/>,访问相应资源时调用的方法,Identity属性是一个IIdentity接口成员,它有三个属性:
AuthenticationType |
获取所使用的身份验证的类型。 |
IsAuthenticated |
获取一个值,该值指示是否验证了用户。 |
Name |
获取当前用户的名称。 |
这些属性和方法可以使用页面(Page) 对象的User属性来进行调用,非常方便。
至此,ASP.NE Forms 身份验证框架就介绍完了,希望对你的工作或学习有所帮助。转载请注明出处。