Rocho.J

人脑是不可靠的, 随时记录感悟并且经常重复!

 

学习笔记 --- Asp.Net 中的身份验证和授权管理

Web项目最终是要在企业内部网( Intranet )或者互联网( Internet )环境下部署的即便是在企业Intranet环境下也存在跨国企业或者连锁式分布企业于是将会有这样的需求通过互联网将同一企业的多个局域网互联起来因此无论是Intranet还是Internet都具有严格的安全要求可以设想一下允许任意用户访问其所有资源的web项目将严重降低用户信任度对于电子商务类的网站更是无法接受即使是资料共享类的网站项目(个人博客、图书馆等), 其后台管理界面也不会允许任意用户访问的.

  

可见无论是何种类型的Web项目安全都是无法回避的课题那么安全是如何保证的呢?  安全是个包括用户、机房环境、服务器、防火墙、信息服务提供商(ISP)、网站项目编码、数据库等等一系列相关问题在内的系统工程其范畴涉及从用户发送请求开始到接收响应的通信过程中所有相关事务听起来好像很复杂实际上也确实是但人类的聪明之处在于总能够将非常复杂的东西分解为一个个相对简单的部分在保证Web项目安全的过程中涉及到很多方面每一个方面总能够找到相关职位的人来处理服务器安全有网络工程师、数据库安全有DBA、通信过程的安全有ISP等等对于Web项目的开发人员来说安全就是保证源代码不被非法用户获取或修改、不同类别的用户只能访问其允许那部分资源.

  

对于Web开发人员的第一种安全主要通过加密手段来处理在代码中对用户名和密码等敏感信息进行加密处理、对关键的配置文件(*.config)进行加密处理、对关键类库文件(*.dll)进行强名称处理并放到GAC

对于Web开发人员更为重要的第二种安全需要解决两个方面的问题第一、用户身份验证即判断用户是否为已登录的合法用户第二、授予用户相应的权限对已验证身份的用户授予或拒绝特定的权限来限制用户访问.NET技术中, ASP.NET组件与FrameworkIIS协同工作以提供Web应用程序的安全要求参见下图表示了Asp.Net身份验证及授权管理信息.

 

Http协议是断开的访问协议也就是说在客户端发送请求并得到服务器的响应后服务器将销毁页面对象当客户端再次请求时将重新创建一个新的页面对象所以验证用户的工作需要在每一次请求中都进行处理. Asp.Net采用的解决方案是在客户端浏览器(Cookie)中保存一个表示用户的票据在浏览器的每次请求中都附带这个票据服务器收到请求后检查这个票据在客户端注销的时候就删除客户端保存的票据.

  

1. Asp.Net中支持四中验证模式: Windows验证、Forms验证、Passport验证、None. 

这四种验证方式中, Passport验证是微软的专有技术它允许用户使用Passport帐户同时管理其操作系统、邮件、MSNLiveSpace等多种应用也就是只要用户登录了Passport帐户就可以直接访问操作系统、邮件、MSN等程序而不再需要进行身份验证操作但是由于版权、使用费用的问题似乎没有流行开来. None表示不验证没有什么可说的最终4种验证方式中真正使用的只有Windows验证和Forms验证两种也是本篇主要讨论的问题.

  

由上图可以看出无论是Windows验证还是Forms验证其关于验证过程的处理流程是很相似的区别是验证和颁发票据的时机不同: Windows验证是在IIS和服务器的帐户管理功能之间验证客户端用户并发送票据(或者称为授权信息Authorization); Forms验证是在HttpApplication处理管道的页面处理流程中完成的具体是在页面处理流程的PageLoadPageLoadComplete事件之间执行的控件的Click事件中完成验证客户端的工作并发送票据的.

  

2. 先来看Windows验证

配置Windows验证IIS中网站项目上右击并选择属性目录安全性 ---> 认证和访问控制中点击编辑去掉匿名访问只勾选集成Windows验证即可之后再网站的配置文件(web.config)找到system.web配置节中找到authentication元素的mode属性将其值修改为Windows就完成了Windows验证方式的配置.

<system.web>
<authentication mode = ”Windows” />
</system.web>

 

Windows验证的请求过程:

当客户端浏览器(通常是IE)Web服务器发送第一个请求(Get请求)服务器中IIS接收到请求后先检查自身配置发现需要进行Windows身份验证而客户端请求中没有附带任何身份验证信息因此服务器直接返回401未授权信息给客户端并提示客户端需要输入用户名和密码当客户端提供了账户名和密码后第二次发送Get请求到服务器的IIS(该请求中附带了Authorization授权信息), IIS接受到请求后将到服务器的用户管理组件中验证是否有该用户如果服务器上没有该用户IIS会仍然返回401未授权信息给客户端如果服务器上有该用户那么Windows操作系统将会获取当前用户的信息并传送给IIS, 之后IIS再将用户信息通过aspnet_iisapi.dll传递给Asp.Net网站应用程序之后就进入了HttpApplication处理管道HttpApplication的验证事件(AuthenticateRequest)网站应用程序将利用IIS传递的用户信息构建System.Security.Principal.WindowsPrincipal类型的对象用于在程序中表示当前请求的用户对象这个对象同时包含用户和用户组信息我们可以通过HttpContext对象中的User属性在管道的处理流程中获得用户信息也可以在页面对象(Page)User属性中获得用户信息.

 

Window身份验证方式要求客户端的浏览器必须使用IE浏览器只有IE浏览器可以与IIS服务器传递Windows帐户信息这种方式非常适合在企业内部管理系统中使用但是不适合在互联网环境中使用.

示例代码:

//WindowsAuthenticate.aspx

代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="WindowsAuthentication.aspx.cs" Inherits="WindowsAuthentication" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="WinAuthen" runat="server"></asp:TextBox>
</div>
</form>
</body>
</html>

 

//WindowsAuthenticate.aspx.cs

代码
//WindowsAuthenticate.aspx.cs
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

public partial class WindowsAuthentication : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.WinAuthen.Text = User.Identity.Name + ":" + User.Identity.AuthenticationType;
}
}

 

3. 再来看Forms验证

在介绍Forms验证之前先说说应用程序中的用户表示:

由于各种各样的应用程序中都可能需要对用户进行管理, .NET专门定义了在程序中表示用户的方式: System.Security.Principal命名空间下的IPrincipal定义了用户对象的抽象接口, IIdentity定义了用户标识的抽象接口其中IPrincipal中定义了一个返回值为IIdentity的属性Identity和方法IsInRole(stirng role); IIdentity中定义了用户验证类型(AuthenticateType)、是否通过验证(IsAuthenticated)、当前用户名(Name)三个属性

.Net同时还为我们定义了多种上述接口的实现类常见的有普通用户验证(GenericIdentityGenericPrincipal)Windows用户验证(WindowsIdentityWindowsPrincipal)Forms验证(System.Web.Security.FormsIdentity, 需要配合System.Security.Principal中的GenericPrincipal使用)

 

关于Forms验证:

配置Forms验证IIS中网站项目上右击并选择属性目录安全性 ---> 认证和访问控制中点击编辑只勾选匿名访问即可(千万不要修改默认的用户和密码). 之后再网站的配置文件(web.config)找到system.web配置节中找到authentication元素的mode属性将其值修改为Forms, 并在authentication配置节中添加类似于

<form name=Cait loginUrl=login.aspx defaultUrl=default.aspx protection=All ></forms>的配置信息关于该配置中的几个属性

loginUrldefaultUrl分别表示登陆页和默认首页的url

name是保存TicketCookie的名称

protection是对Cookie的保护措施(Encryption表示仅加密、Validation表示仅签名检查、All表示前两项都进行、None表示不保护)

slidingExpiration用来设置Cookie的过期方式, true表示使用滑动过期时间, false表示绝对过期时间(默认false)

timeout用类设置Cookie的过期时间分钟为单位slidingExpiration为滑动过期timeout表示滑动过期的时间间隔slidingExpiration是绝对过期timeout表示绝对过期的时间为登陆时间+timeout的值.

 

Forms验证的请求过程:

当客户端浏览器第一次向服务器发GET请求时服务器中的IIS接收请求. IIS检查请求资源的后缀名如果是*.htm等静态资源, IIS会直接找到资源并返回给客户端浏览器如果不是*.htm等静态资源IIS会先查找应用程序配置中的扩展名配置列表如果找不到相关扩展名IIS将返回无法找到资源的错误如果找到了则将请求转发给处理该类请求的动态类库处理(.net技术中通常为aspnet_iisapi.dll). 

aspnet_iisapi.dll首先查找配置文件根据配置文件找到\相关资源的处理程序之后由w3wp.exe进程创建应用程序域并在应用程序域中创建HttpRuntime执行环境之后再创建HttpContext对象(其中含HttpRequestHttpResponseCookieSession等对象)后进入应用程序处理管道开始请求处理

在应用程序处理管道的十几个事件中在第二个事件(AuthenticateRequest事件)中开始身份验证过程如果身份验证失败(无票据Ticket), 则用户名为空串相应的页面对象的User对象的Identity中的name也是空串如果验证成功(Ticket)则通过Cookie获得票据信息进程创建程序中的用户表示(例如可以通过页面的User对象获得用户信息), 然后继续执行应用程序处理管道事件在执行完PreRequestHandlerExecute事件之后将进入页面处理管道(页面处理流程). 在页面处理流程中如果用户名为空串IsAuthentication方法返回false, 这是通常根据配置文件中的<forms>配置节直接重定向到Login页面如果用户名不为空表示认证通过则绘制客户端所请求的页面并继续走完应用程序处理管道后将请求页面发送给客户端浏览器.

由于客户输入域名直接请求的是默认页default.aspx, 由于第一次请求没有附带票据所以用户名肯定为空则根据配置节中的<forms>直接重定向到Login页面.

在第二次请求中客户端浏览器向服务器发送Post请求服务器IIS接受请求后仍然按照aspnet_iisapi.dll ---> w3wp.exe ---> HttpRuntime ---> HttpApplication 的顺序处理由于请求的是Login.aspx页面默认情况下这个页面任何人都具有访问权限因此IsAuthenticate()方法可以通过在之后的页面处理流程中将激发登录按钮的事件处理器我们在按钮的事件处理器中执行创建票据和发票的过程并将票据保存在客户端浏览器中然后继续走完应用程序处理流程.

在之后的第三次请求中客户端浏览器首先检查本地的Cookie, 如果发现Cookie文件的名称和请求资源的域名相同则客户端浏览器会讲Cookie中的内容以键值对的方式一并发送到服务器中服务器端IIS仍然走应用程序处理管道在其第二个事件(AuthenticateRequest事件中), 发现Cookie不为空时将从Cookie去中的帐户信息保存在HttpContextUser对象中于此同时页面对象中也有一个User的属性该属性其实就是HttpContextUser, 我们可以再页面后台文件(.cs)通过页面对象的User获得帐户信息在之后的第四次、第五次等数次请求中验证过程都在每次请求的AuthencateRequest事件中进行了处理我们可以很方便的从页面对象中取得用户名称、用户组等信息如果用户没有点击注销那么该用户的信息将始终存在在用户点击了注销按钮后讲调用SingOut()方法Cookie中的票据删除(修改Cookie过期时间), 之后用户再次请求将直接重定向到Login页面我们可以通过子在配置文件的<authorization>配置节(不常用)<location>配置节中规定哪些用户可以访问这样就可以实现比较完善的管理功能了.

 

a). 使用系统的System.Web.Security.FormsAuthentication

Asp.Net中默认已经实现了对于Forms验证的直接支持因此我们可以直接使用System.Web.Security.FormsAuthentication实现类来完成Forms验证操作.

 

值得注意的是使用系统默认的Forms验证方式一定要自定义登陆窗体(页面). 因为默认的登录窗体名称为Login.aspx, 此名称可以在配置文件的forms元素中进行配置但是Asp.net网站会根据Login.aspx创建Login的类型.Net类库System.Web.UI.WebControls中也有一个名称为Login的控件类型这样便会引起冲突因此一定要为Login.aspx登陆页面自定义一个命名空间以避免冲突.

 

FormsAuthentication类的RedirectFromLoginPage()方法实现了登陆处理中的创建票据、创建Cookie、加入到Response中的工作然后将用户送回原来访问的Url, 若直接访问Login页面则将用户送回网站首页注意该方法没有过期时间的参数过期时间的设置在配置文件web.config中的forms元素的slidingExpirationtimeout属性中配置.

也可以使用SetAuthCookie()方法仅创建票据而由程序员决定登陆之后的重定向.

注销就是删除用户的Cookie, 可以采用SingOut()方法进行不过在执行SingOut()方法后需要调用RedirectToLoginPage()方法将用户重定向到登陆页面.

 

//为简单起见这里直接将用户名和密码写在<forms>元素中的<credentials>节点中.

//LoginPage.aspx

代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LoginPage.aspx.cs" Inherits="LoginPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txt_username" runat="server"></asp:TextBox><br />
<asp:TextBox ID="txt_userpass" runat="server"></asp:TextBox><br />
<asp:LinkButton ID="lbtn_login" runat="server" onclick="lbtn_login_Click">登陆</asp:LinkButton>
</div>
</form>
</body>
</html>

 

//LoginPage.aspx.cs

代码
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;


public partial class LoginPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
protected void lbtn_login_Click(object sender, EventArgs e)
{
if (IsValid)
{
string name = this.txt_username.Text.Trim();
string pass = this.txt_userpass.Text.Trim();

//注意: 未知的编码方面的原因, 造成web.config的<credentials>节点用md5计算散列码, 结果不正确.

//通常做法: 避免向服务器端传递明文, 可以先在Javascript中计算MD5散列码, 然后再发送到服务器端. 服务器端接收到后需要掉DAL并到数据库中验证.

//获得用户输入密码的散列码:
byte[] buffer;
buffer
= System.Text.Encoding.GetEncoding("utf-8").GetBytes(pass);
buffer
= System.Security.Cryptography.MD5CryptoServiceProvider.Create().ComputeHash(buffer);
string password = BitConverter.ToString(buffer).Replace("-", "");

//string password = FormsAuthentication.HashPasswordForStoringInConfigFile(pass,"SHA1");

if (FormsAuthentication.Authenticate(name, password)) //是否通过验证
{
FormsAuthentication.RedirectFromLoginPage(name,
false);
//FormsAuthentication.SetAuthCookie(name, false); //仅创建票据, 手动跳转
//this.Response.Redirect("default.aspx");
}
}
}
}

 

//Default.aspx

 

代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lbl_msg" runat="server" Text="Label"></asp:Label>
<asp:LinkButton ID="logout" runat="server">注销</asp:LinkButton>
</div>
</form>
</body>
</html>

 

//Default.aspx.cs

代码
using System;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.lbl_msg.Text = this.User.Identity.IsAuthenticated ? this.User.Identity.Name + " 已登录! " : " 您还未登录! ";
}
protected void logout_Click(object sender, EventArgs e)
{
System.Web.Security.FormsAuthentication.SignOut();
}
}

 

//web.config

代码
<authentication mode="Forms">
<forms name="Cait" loginUrl="LoginPage.aspx" defaultUrl="Default.aspx" protection="All">
<credentials passwordFormat="Clear">
<user name="Admin" password="0192023A7BBD73250516F069DF18B500" />
</credentials>
</forms>
</authentication>

<authorization>
<deny users="?"/>
</authorization>

 

b). 使用Global.aspxIHttpModule实现类来自定义Forms验证过程(使用IHttpModule是常用做法): 

1.) 解决用户点击登录按钮后的票据生成和保存问题.

//LoginPage.aspx

代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LoginPage.aspx.cs" Inherits="LoginPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txt_username" runat="server"></asp:TextBox><br />
<asp:TextBox ID="txt_userpass" runat="server"></asp:TextBox><br />
<asp:LinkButton ID="lbtn_login" runat="server" onclick="lbtn_login_Click">登陆</asp:LinkButton>
</div>
</form>
</body>
</html>

 

//Loginpage.aspx.cs

代码
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;


public partial class LoginPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
protected void lbtn_login_Click(object sender, EventArgs e)
{
if (IsValid)
{
string name = this.txt_username.Text.Trim();
string pass = this.txt_userpass.Text.Trim();

//获得用户输入密码的散列码:
byte[] buffer;
buffer
= System.Text.Encoding.GetEncoding("utf-8").GetBytes(pass);
buffer
= System.Security.Cryptography.MD5CryptoServiceProvider.Create().ComputeHash(buffer);
string password = BitConverter.ToString(buffer).Replace("-", "");

#region 这里为简单, 直接通过配置文件读取账户名和密码. 使用Authenticate()方法验证
if (FormsAuthentication.Authenticate(name, password)) //是否通过验证
{
//FormsAuthentication.RedirectFromLoginPage(name, false);

//验证通过, 创建票据
System.Web.Security.FormsAuthenticationTicket ticket = new System.Web.Security.FormsAuthenticationTicket(2, name, DateTime.Now, DateTime.Now.AddDays(7), true, string.Empty);

//在加入到Cookie之前, 先进行加密
string cookiestring = System.Web.Security.FormsAuthentication.Encrypt(ticket);

//创建Cookie, 可直接使用任意串做Cookie名. 这里利用FormsAuthentication类从配置文件里读取
HttpCookie cookie = new HttpCookie(System.Web.Security.FormsAuthentication.FormsCookieName);
cookie.Value
= cookiestring;
cookie.Expires
= DateTime.Now.AddDays(3);

//将Cookie发送到浏览器
this.Response.Cookies.Add(cookie);
//this.Response.SetCookie(cookie); //更新Cookie
this.Response.Redirect("default.aspx");
}
#endregion

#region 这个验证过程也可以通过调用BLL层、DAL层访问数据库来完成(常见做法)
//这里忽略访问数据库的过程
#endregion
}
}
}

 

2.) 自定义类CustomAuthentication.cs实现IHttpModule接口IHttpModuleAuthenticateRequest事件中编写自定义的认证处理过程并创建程序中的用户标识当然最后千万不能忘了要在配置文件的<httpModules>配置节中注册我们自定义的类CustomAuthentication. 这样的做的好处程序员将从状态管理的代码中解放出来我们只要在页面调用IsAuthenticate()方法即可也不需要手动的维护跳转的工作更方便的是我们可以随时通过页面的User对象获得用户信息(要注意这里的用户信息是在程序内的表示继承自IPrincipalIIdentity两个接口).

//CustomAuthentication.cs

代码
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

/// <summary>
/// Summary description for CustomAuthentication
/// </summary>
public class CustomAuthentication : IHttpModule
{
#region IHttpModule Members

public void Dispose()
{

}

public void Init(HttpApplication application) //这里的上下文, 容易和HttpContext弄混, 改为application
{
//注册AuthenticateRequest事件的处理器
application.AuthenticateRequest += new EventHandler(application_AuthenticateRequest);
}

void application_AuthenticateRequest(object sender, EventArgs e)
{
//取得appliation中cookie对象, 并从中取得用户标识; sender其实就是application(通过参数传递application的引用)
HttpApplication application = sender as HttpApplication;

//两种从application中取Cookie的方式均可
HttpCookie cookie = application.Request.Cookies[FormsAuthentication.FormsCookieName]; //从配置文件中取, 也可用固定的串hardcode进程序中
//HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName]; //从上下文对象中取Request中的Cookie

string username = string.Empty;
if (cookie != null)
{
//从Cookie中取加密后的票据, 并反序列化得到票据
string cookiestring = cookie.Value;
FormsAuthenticationTicket ticket
= FormsAuthentication.Decrypt(cookiestring);

//从票据中取用户名
username = ticket.Name;
}

//注意: username为空表示验证失败
//用户信息需要编程程序中的标识方式, 可以GenericPrincipal、WindowsPrincipal, Forms常用GenericPrincipal
System.Security.Principal.GenericIdentity identity = new System.Security.Principal.GenericIdentity(username);
System.Security.Principal.GenericPrincipal principal
= new System.Security.Principal.GenericPrincipal(identity, new string[] { "Admin","Users" }); //用户的名称和组信息

//为了在程序中方便获得用户信息, 将用户信息保存到HttpContext中, 进行状态管理
HttpContext hc = application.Context;
//hc.Items.Add("User", principal); //可以放到集合中, 也可以直接放到User中
hc.User = principal;
}

#endregion
}

 

//web.config

<httpModules>
<add name="CustomPrincipal" type="CustomAuthentication"/>
</httpModules>

 

3.) 上述步骤完成后我们就可以在其他的后台页面中通过UserIdentity获得用户信息即在页面中使用用户标识

//default.aspx

代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lbl_msg" runat="server" Text="Label"></asp:Label><br />
<asp:LinkButton ID="logout" runat="server" onclick="logout_Click">注销</asp:LinkButton>
</div>
</form>
</body>
</html>

 

//default.aspx.cs

 

代码
using System;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.lbl_msg.Text = this.User.Identity.IsAuthenticated ? this.User.Identity.Name + " 已登录! " : " 您还未登录! ";
}
protected void logout_Click(object sender, EventArgs e)
{
//创建新Cookie对象, 并修改过期时间
HttpCookie cookie = new HttpCookie(System.Web.Security.FormsAuthentication.FormsCookieName);
cookie.Expires
= DateTime.Now.AddDays(-7);

this.Response.Cookies.Add(cookie);
//this.Response.Redirect("LoginPage.aspx");
this.Response.Redirect(this.Request.Path); //重定请求刚才的资源
}
}

 

//web.config

代码
<authentication mode="Forms">
<forms name="Cait" loginUrl="LoginPage.aspx" defaultUrl="Default.aspx" protection="All">
<credentials passwordFormat="Clear">
<user name="Admin" password="0192023A7BBD73250516F069DF18B500" />
</credentials>
</forms>
</authentication>

<authorization>
<deny users="?"/>
</authorization>

 

最后关于授权:

Asp.net的授权机制为我们提供了一种特别方便的组织资源的方式由于配置文件是有继承关系的所以我们可以将某类资源放在同一个文件夹中再配上一个配置文件用来规定有哪些用户可以访问这样就可以实现对资源的分层次管理的要求.

虽然也可以在应用程序处理管道的AuthorizeRequest事件中进行授权处理但实际上我们很少很少哪么做关于授权有几个事情需要留意下:

1.) 默认登录页面不受配置文件中的规则限制.

2.) 配置元素中只有两种行为, allow 和 deny; 而每种行为都有3个属性可以使用分别是: usersrolesverbs. 前两个不用解释AuthenticateRequest的事件中我们创建的用户对象就包含这些内容Verbs用来分隔Http协议的请求方法可以有多个(: verbs = GET,POST,HEAD,DEBUG), 注意大小写一定要正确.

3.) 两个特殊的符号?表示匿名用户*表示所有用户.

4.)配置规则是从上到下依次生效的比如你可以先定义规则<allow users=AA>, 紧跟着第二行定义<deny user=*>; 哪么上边的优先执行最终结果就是只允许AA访问.

5.) 最后一个事情就是关于资源的管理有两种配置节一种是<authorization>, 这种适合大范围限制某些资源如整个文件夹另外一种是<location>, 这种适合针对某个资源进行配置用于较小的范围

下面是两个例子:

代码
<authorization>
<allow users="AA"/>
<deny users="*"/>
</authorization>

<location path="default.aspx">
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</location>

 

额外多说几句配置文件中的<location>配置节主要用来添加相同的配置节元素比如如果外边不加<location>配置节则默认只允许有一个<system.web>但是外边套一个<location>就允许有两个<system.web>配置节了.

posted on 2011-01-20 02:23  RJ  阅读(2308)  评论(0编辑  收藏  举报

导航