0

0

ASP.NET Forms身份认证详解

高洛峰

高洛峰

发布时间:2017-02-10 17:16:23

|

1421人浏览过

|

来源于php中文网

原创

在这篇文章中,不会涉及asp.net的登录系列控件以及membership的相关话题,我只想用比较原始的方式来说明在asp.net中是如何实现身份认证的过程。

ASP.NET身份认证基础

在开始今天的内容之前,我想有二个最基础的问题首先要明确:

1. 如何判断当前请求是一个已登录用户发起的?

2. 如何获取当前登录用户的登录名?

在标准的ASP.NET身份认证方式中,上面二个问题的答案是:

1. 如果Request.IsAuthenticated为true,则表示是一个已登录用户。

2. 如果是一个已登录用户,访问HttpContext.User.Identity.Name可获取登录名(都是实例属性)。

接下来,本文将会围绕上面二个问题展开,请继续阅读。

ASP.NET身份认证过程

在ASP.NET中,整个身份认证的过程其实可分为二个阶段:认证与授权。

1. 认证阶段:识别当前请求的用户是不是一个可识别(的已登录)用户。

2. 授权阶段:是否允许当前请求访问指定的资源。

这二个阶段在ASP.NET管线中用AuthenticateRequest和AuthorizeRequest事件来表示。

在认证阶段,ASP.NET会检查当前请求,根据web.config设置的认证方式,尝试构造HttpContext.User对象供我们在后续的处理中使用。在授权阶段,会检查当前请求所访问的资源是否允许访问,因为有些受保护的页面资源可能要求特定的用户或者用户组才能访问。所以,即使是一个已登录用户,也有可能会不能访问某些页面。当发现用户不能访问某个页面资源时,ASP.NET会将请求重定向到登录页面。

受保护的页面与登录页面我们都可以在web.config中指定,具体方法可参考后文。

在ASP.NET中,Forms认证是由FormsAuthenticationModule实现的,URL的授权检查是由UrlAuthorizationModule实现的。

如何实现登录与注销

前面我介绍了可以使用Request.IsAuthenticated来判断当前用户是不是一个已登录用户,那么这一过程又是如何实现的呢?

为了回答这个问题,我准备了一个简单的示例页面,代码如下:


用户状态
<% if( Request.IsAuthenticated ) { %> 当前用户已登录,登录名:<%= Context.User.Identity.Name.HtmlEncode() %>
<% } else { %> 当前用户还未登录。 <% } %>

页面显示效果如下:

ASP.NET Forms身份认证详解

根据前面的代码,我想现在能看到这个页面显示也是正确的,是的,我目前还没有登录(根本还没有实现这个功能)。

下面我再加点代码来实现用户登录。页面代码:


普通登录
登录名:

现在页面的显示效果:

ASP.NET Forms身份认证详解

登录与退出登录的实现代码:


public void Logon() 
{ 
 FormsAuthentication.SignOut(); 
} 
 
public void NormalLogin() 
{ 
 // ----------------------------------------------------------------- 
 // 注意:演示代码为了简单,这里不检查用户名与密码是否正确。 
 // ----------------------------------------------------------------- 
 
 string loginName = Request.Form["loginName"]; 
 if( string.IsNullOrEmpty(loginName) ) 
  return; 
  
 FormsAuthentication.SetAuthCookie(loginName, true); 
 
 TryRedirect(); 
}

现在,我可试一下登录功能。点击登录按钮后,页面的显示效果如下:

ASP.NET Forms身份认证详解

从图片的显示可以看出,我前面写的NormalLogin()方法确实可以实现用户登录。
当然了,我也可以在此时点击退出按钮,那么就回到了图片2的显示。

写到这里,我想有必要再来总结一下在ASP.NET中实现登录与注销的方法:

1. 登录:调用FormsAuthentication.SetAuthCookie()方法,传递一个登录名即可。

2. 注销:调用FormsAuthentication.SignOut()方法。

保护受限制的页面

在一个ASP.NET网站中,有些页面会允许所有用户访问,包括一些未登录用户,但有些页面则必须是已登录用户才能访问,还有一些页面可能会要求特定的用户或者用户组的成员才能访问。这类页面因此也可称为【受限页面】,它们一般代表着比较重要的页面,包含一些重要的操作或功能。

为了保护受限制的页面的访问,ASP.NET提供了一种简单的方式:可以在web.config中指定受限资源允许哪些用户或者用户组(角色)的访问,也可以设置为禁止访问。

比如,网站有一个页面:MyInfo.aspx,它要求访问这个页面的访问者必须是一个已登录用户,那么可以在web.config中这样配置:


 
  
   
    
   
  

为了方便,我可能会将一些管理相关的多个页面放在Admin目录中,显然这些页面只允许Admin用户组的成员才可以访问。对于这种情况,我们可以直接针对一个目录设置访问规则:


 
  
   
    
    
   
  

这样就不必一个一个页面单独设置了,还可以在目录中创建一个web.config来指定目录的访问规则,请参考后面的示例。

在前面的示例中,有一点要特别注意的是:

1. allow和deny之间的顺序一定不能写错了,UrlAuthorizationModule将按这个顺序依次判断。

2. 如果某个资源只允许某类用户访问,那么最后的一条规则一定是

在allow和deny的配置中,我们可以在一条规则中指定多个用户:

1. 使用users属性,值为逗号分隔的用户名列表。

2. 使用roles属性,值为逗号分隔的角色列表。

3. 问号 (?) 表示匿名用户。

4. 星号 (*) 表示所有用户。

登录页不能正常显示的问题

有时候,我们可能要开发一个内部使用的网站程序,这类网站程序要求 禁止匿名用户的访问,即:所有使用者必须先登录才能访问。因此,我们通常会在网站根目录下的web.config中这样设置:


 
  

对于我们的示例,我们也可以这样设置。此时在浏览器打开页面时,呈现效果如下:

ASP.NET Forms身份认证详解

从图片中可以看出:页面的样式显示不正确,最下边还多出了一行文字。

这个页面的完整代码是这样的(它引用了一个CSS文件和一个JS文件):


<%@ Page Language="C#" CodeFile="Default.aspx.cs" Inherits="_Default" %> 
 
 
 FormsAuthentication DEMO - http://www.php.cn/;/title> 
 <link type="text/css" rel="Stylesheet" href="css/StyleSheet.css" /> 
</head> 
<body> 
 <fieldset><legend>普通登录</legend><form action="<%= Request.RawUrl %>" method="post"> 
  登录名:<input type="text" name="loginName" style="width: 200px" value="Fish" /> 
  <input type="submit" name="NormalLogin" value="登录" /> 
 </form></fieldset>  
  
 <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" name="Logon" value="退出" /> 
  <% } else { %> 
   <b>当前用户还未登录。</b> 
  <% } %>    
 </form></fieldset>  
  
 <p id="hideText"><i>不应该显示的文字</i></p> 
 <script type="text/javascript" src="js/JScript.js"></script> 
</body> 
</html></pre><p>页面最后一行文字平时不显示是因为JScript.js中有以下代码:</p>
<p class="jb51code"><br></p><pre class="brush:js;">document.getElementById("hideText").setAttribute("style", "display: none");</pre><p>这段JS代码能做什么,我想就不用再解释了。虽然这段JS代码没什么价值,但我主要是想演示在登录页面中引用JS的场景。</p>
<p>根据前面图片,我们可以猜测到:应该是CSS和JS文件没有正确加载造成的。为了确认就是这样原因,我们可以打开FireBug再来看一下页面加载情况:</p>
<p style="text-align: center"><img id="theimg" alt="ASP.NET Forms身份认证详解" src="https://img.php.cn/upload/article/000/000/013/ee61dc07131cdb960df03e9c6918ada6-4.png"    style="max-width:90%"  style="max-width:90%" title="ASP.NET Forms身份认证详解"></p>
<p>根据FireBug提供的线索我们可以分析出,页面在访问CSS, JS文件时,其实是被重定向到登录页面了,因此获得的结果肯定也是无意义的,所以就造成了登录页的显示不正确。</p>
<p>还记得【授权】吗?<br>是的,现在就是由于我们在web.config中设置了不允许匿名用户访问,因此,所有的资源也就不允许匿名用户访问了,包括登录页所引用的CSS, JS文件。当授权检查失败时,请求会被重定向到登录页面,所以,登录页本身所引用的CSS, JS文件最后得到的响应内容其实是登录页的HTML代码,最终导致它们不能发挥作用,表现为登录页的样式显示不正确,以及引用的JS文件也不起作用。</p>
<p>不过,有一点比较奇怪:为什么访问登录页面时,没有发生重定向呢?</p>
<p>原因是这样的:在ASP.NET内部,当发现是在访问登录面时,会设置HttpContext.SkipAuthorization = true (其实是一个内部调用),这样的设置会告诉后面的授权检查模块:跳过这次请求的授权检查。 因此,登录页总是允许所有用户访问,但是CSS文件以及JS文件是在另外的请求中发生的,那些请求并不会要跳过授权模块的检查。</p>
<p>为了解决登录页不能正确显示的问题,我们可以这样处理:</p>
<p>1. 在网站根目录中的web.config中设置登录页所引用的JS, CSS文件都允许匿名访问。</p>
<p>2. 也可以直接针对JS, CSS目录设置为允许匿名用户访问。</p>
<p>3. 还可以在CSS, JS目录中创建一个web.config文件来配置对应目录的授权规则。可参考以下web.config文件:</p>
<p class="jb51code"><br></p><pre class="brush:xml;"><?xml version="1.0"?> 
<configuration> 
 <system.web> 
  <authorization> 
   <allow users="*"/> 
  </authorization> 
 </system.web> 
</configuration></pre><p>第三种做法可以不修改网站根目录下的web.config文件。</p>
<p><strong>注意:在IIS中看到的情况就和在Visual Studio中看到的结果就不一样了。</strong> 因为,像js, css, image这类文件属于静态资源文件,IIS能直接处理,不需要交给ASP.NET来响应,因此就不会发生授权检查失败,所以,如果这类网站部署在IIS中,看到的结果又是正常的。</p>
<p><strong>认识Forms身份认证</strong></p>
<p>前面我演示了如何用代码实现登录与注销的过程,下面再来看一下登录时,ASP.NET到底做了些什么事情,它是如何知道当前请求是一个已登录用户的?</p>
<p>在继续探索这个问题前,我想有必要来了解一下HTTP协议的一些特点。</p>
<p>HTTP是一个无状态的协议,无状态的意思可以理解为: WEB服务器在处理所有传入请求时,根本就不知道某个请求是否是一个用户的第一次请求与后续请求,或者是另一个用户的请求。 WEB服务器每次在处理请求时,都会按照用户所访问的资源所对应的处理代码,从头到尾执行一遍,然后输出响应内容, WEB服务器根本不会记住已处理了哪些用户的请求,因此,我们通常说HTTP协议是无状态的。</p>
<p>虽然HTTP协议与WEB服务器是无状态,但我们的业务需求却要求有状态,典型的就是用户登录,在这种业务需求中,要求WEB服务器端能区分某个请求是不是一个已登录用户发起的,或者当前请求是哪个用户发出的。在开发WEB应用程序时,我们通常会使用Cookie来保存一些简单的数据供服务端维持必要的状态。既然这是个通常的做法,那我们现在就来看一下现在页面的Cookie使用情况吧,以下是我用FireFox所看到的Cookie列表:</p>
<p style="text-align: center"><img id="theimg" alt="ASP.NET Forms身份认证详解" src="https://img.php.cn/upload/article/000/000/013/c7d43a0e4d4a46b7a7bf777c1c075aea-5.png"    style="max-width:90%"  style="max-width:90%" title="ASP.NET Forms身份认证详解"></p>
<p>这个名字:LoginCookieName,是我在web.config中指定的:</p>
<p class="jb51code"><br></p><pre class="brush:php;toolbar:false"><authentication mode="Forms" > 
 <forms cookieless="UseCookies" name="LoginCookieName" loginUrl="~/Default.aspx"></forms> 
</authentication></pre><p>在这段配置中,我不仅指定的登录状态的Cookie名,还指定了身份验证模式,以及Cookie的使用方式。</p>
<p>为了判断这个Cookie是否与登录状态有关,我们可以在浏览器提供的界面删除它,然后刷新页面,此时页面的显示效果如下:</p><div class="aritcle_card flexRow">
							<div class="artcardd flexRow">
								<a class="aritcle_card_img" href="/ai/2468" title="红墨"><img
										src="https://img.php.cn/upload/ai_manual/001/246/273/176715129988131.png" alt="红墨"></a>
								<div class="aritcle_card_info flexColumn">
									<a href="/ai/2468" title="红墨">红墨</a>
									<p>一站式小红书图文生成器</p>
								</div>
								<a href="/ai/2468" title="红墨" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
							</div>
						</div>
<p style="text-align: center"><img id="theimg" alt="ASP.NET Forms身份认证详解" src="https://img.php.cn/upload/article/000/000/013/c7d43a0e4d4a46b7a7bf777c1c075aea-6.png"    style="max-width:90%"  style="max-width:90%" title="ASP.NET Forms身份认证详解"></p>
<p>此时,页面显示当前用户没有登录。</p>
<p>为了确认这个Cookie与登录状态有关,我们可以重新登录,然后再退出登录。<br>发现只要是页面显示当前用户未登录时,这个Cookie就不会存在。</p>
<p>事实上,通过SetAuthCookie这个方法名,我们也可以猜得出这个操作会写一个Cookie。<br><strong>注意:本文不讨论无Cookie模式的Forms登录。</strong></p>
<p>从前面的截图我们可以看出:虽然当前用户名是 Fish ,但是,Cookie的值是一串乱码样的字符串。<br>由于安全性的考虑,ASP.NET对Cookie做过加密处理了,这样可以防止恶意用户构造Cookie绕过登录机制来模拟登录用户。如果想知道这串加密字符串是如何得到的,那么请参考后文。</p>
<p><strong>小结:</strong></p>
<p>1. Forms身份认证是在web.config中指定的,我们还可以设置Forms身份认证的其它配置参数。</p>
<p>2. Forms身份认证的登录状态是通过Cookie来维持的。</p>
<p>3. Forms身份认证的登录Cookie是加密的。</p>
<p><strong>理解Forms身份认证</strong></p>
<p>经过前面的Cookie分析,我们可以发现Cookie的值是一串加密后的字符串,现在我们就来分析这个加密过程以及Cookie对于身份认证的作用。</p>
<p>登录的操作通常会检查用户提供的用户名和密码,因此登录状态也必须具有足够高的安全性。在Forms身份认证中,由于登录状态是保存在Cookie中,而Cookie又会保存到客户端,因此,为了保证登录状态不被恶意用户伪造, ASP.NET采用了加密的方式保存登录状态。为了实现安全性,ASP.NET采用【Forms身份验证凭据】(即FormsAuthenticationTicket对象)来表示一个Forms登录用户,加密与解密由FormsAuthentication的Encrypt与Decrypt的方法来实现。</p>
<p>用户登录的过程大致是这样的:</p>
<p>1. 检查用户提交的登录名和密码是否正确。</p>
<p>2. 根据登录名创建一个FormsAuthenticationTicket对象。</p>
<p>3. 调用FormsAuthentication.Encrypt()加密。</p>
<p>4. 根据加密结果创建登录Cookie,并写入Response。</p>
<p>在登录验证结束后,一般会产生重定向操作,那么后面的每次请求将带上前面产生的加密Cookie,供服务器来验证每次请求的登录状态。</p>
<p>每次请求时的(认证)处理过程如下:</p>
<p>1. FormsAuthenticationModule尝试读取登录Cookie。</p>
<p>2. 从Cookie中解析出FormsAuthenticationTicket对象。过期的对象将被忽略。</p>
<p>3. 根据FormsAuthenticationTicket对象构造FormsIdentity对象并设置HttpContext.Usre</p>
<p>4. UrlAuthorizationModule执行授权检查。</p>
<p>在登录与认证的实现中,FormsAuthenticationTicket和FormsAuthentication是二个核心的类型,前者可以认为是一个数据结构,后者可认为是处理前者的工具类。</p>
<p>UrlAuthorizationModule是一个授权检查模块,其实它与登录认证的关系较为独立,因此,如果我们不使用这种基于用户名与用户组的授权检查,也可以禁用这个模块。</p>
<p>由于Cookie本身有过期的特点,然而为了安全,FormsAuthenticationTicket也支持过期策略,不过,ASP.NET的默认设置支持FormsAuthenticationTicket的可调过期行为,即:slidingExpiration=true 。这二者任何一个过期时,都将导致登录状态无效。</p>
<p>FormsAuthenticationTicket的可调过期的主要判断逻辑由FormsAuthentication.RenewTicketIfOld方法实现,代码如下:</p>
<p class="jb51code"><br></p><pre class="brush:csharp;">public static FormsAuthenticationTicket RenewTicketIfOld(FormsAuthenticationTicket tOld) 
{ 
 // 这段代码是意思是:当指定的超时时间逝去大半时将更新FormsAuthenticationTicket对象。 
 
 if( tOld == null ) 
  return null; 
  
 DateTime now = DateTime.Now; 
 TimeSpan span = (TimeSpan)(now - tOld.IssueDate); 
 TimeSpan span2 = (TimeSpan)(tOld.Expiration - now); 
 if( span2 > span ) 
  return tOld; 
  
 return new FormsAuthenticationTicket(tOld.Version, tOld.Name, 
  now, now + (tOld.Expiration - tOld.IssueDate), 
  tOld.IsPersistent, tOld.UserData, tOld.CookiePath); 
} 
Request.IsAuthenticated可以告诉我们当前请求是否已经过身份验证,我们来看一下这个属性是如何实现的:

public bool IsAuthenticated 
{ 
 get 
 { 
  return (((this._context.User != null) 
   && (this._context.User.Identity != null)) 
   && this._context.User.Identity.IsAuthenticated); 
 } 
}</pre><p>从代码可以看出,它的返回结果基本上来源于对Context.User的判断。<br>另外,由于User和Identity都是二个接口类型的属性,因此,不同的实现方式对返回值也有影响。</p>
<p>由于可能会经常使用HttpContext.User这个实例属性,为了让它能正常使用, DefaultAuthenticationModule会在ASP.NET管线的PostAuthenticateRequest事件中检查此属性是否为null,如果它为null,DefaultAuthenticationModule会给它一个默认的GenericPrincipal对象,此对象指示一个未登录的用户。</p>
<p>我认为ASP.NET的身份认证的最核心部分其实就是HttpContext.User这个属性所指向的对象。为了更好了理解Forms身份认证,我认为自己重新实现User这个对象的接口会有较好的帮助。</p>
<p>实现自定义的身份认证标识</p>
<p>前面演示了最简单的ASP.NET Forms身份认证的实现方法,即:直接调用SetAuthCookie方法。不过调用这个方法,只能传递一个登录名。但是有时候为了方便后续的请求处理,还需要保存一些与登录名相关的额外信息。虽然知道ASP.NET使用Cookie来保存登录名状态信息,我们也可以直接将前面所说的额外信息直接保存在Cookie中,但是考虑安全性,我们还需要设计一些加密方法,而且还需要考虑这些额外信息保存在哪里才能方便使用,并还要考虑随登录与注销同步修改。因此,实现这些操作还是有点繁琐的。</p>
<p>为了保存与登录名相关的额外的用户信息,我认为实现自定义的身份认证标识(HttpContext.User实例)是个容易的解决方法。<br>理解这个方法也会让我们对Forms身份认证有着更清楚地认识。</p>
<p>这个方法的核心是(分为二个子过程):</p>
<p>1. 在登录时,创建自定义的FormsAuthenticationTicket对象,它包含了用户信息。</p>
<p>2. 加密FormsAuthenticationTicket对象。</p>
<p>3. 创建登录Cookie,它将包含FormsAuthenticationTicket对象加密后的结果。</p>
<p>4. 在管线的早期阶段,读取登录Cookie,如果有,则解密。</p>
<p>5. 从解密后的FormsAuthenticationTicket对象中还原我们保存的用户信息。</p>
<p>6. 设置HttpContext.User为我们自定义的对象。</p>
<p>现在,我们还是来看一下HttpContext.User这个属性的定义:</p>
<p class="jb51code"><br></p><pre class="brush:csharp;">// 为当前 HTTP 请求获取或设置安全信息。 
// 
// 返回结果: 
//  当前 HTTP 请求的安全信息。 
public IPrincipal User { get; set; }</pre><p>由于这个属性只是个接口类型,因此,我们也可以自己实现这个接口。</p>
<p>考虑到更好的通用性:不同的项目可能要求接受不同的用户信息类型。所以,我定义了一个泛型类。</p>
<p class="jb51code"><br></p><pre class="brush:csharp;">public class MyFormsPrincipal<TUserData> : IPrincipal 
 where TUserData : class, new() 
{ 
 private IIdentity _identity; 
 private TUserData _userData; 
 
 public MyFormsPrincipal(FormsAuthenticationTicket ticket, TUserData userData) 
 { 
  if( ticket == null ) 
   throw new ArgumentNullException("ticket"); 
  if( userData == null ) 
   throw new ArgumentNullException("userData"); 
 
  _identity = new FormsIdentity(ticket); 
  _userData = userData; 
 } 
  
 public TUserData UserData 
 { 
  get { return _userData; } 
 } 
 
 public IIdentity Identity 
 { 
  get { return _identity; } 
 } 
 
 public bool IsInRole(string role) 
 { 
  // 把判断用户组的操作留给UserData去实现。 
 
  IPrincipal principal = _userData as IPrincipal; 
  if( principal == null ) 
   throw new NotImplementedException(); 
  else 
   return principal.IsInRole(role); 
 }</pre><p>与之配套使用的用户信息的类型定义如下(可以根据实际情况来定义):</p>
<p class="jb51code"><br></p><pre class="brush:php;toolbar:false">public class UserInfo : IPrincipal 
{ 
 public int UserId; 
 public int GroupId; 
 public string UserName; 
  
 // 如果还有其它的用户信息,可以继续添加。 
 
 public override string ToString() 
 { 
  return string.Format("UserId: {0}, GroupId: {1}, UserName: {2}, IsAdmin: {3}", 
   UserId, GroupId, UserName, IsInRole("Admin")); 
 } 
 
 #region IPrincipal Members 
 
 [ScriptIgnore] 
 public IIdentity Identity 
 { 
  get { throw new NotImplementedException(); } 
 } 
 
 public bool IsInRole(string role) 
 { 
  if( string.Compare(role, "Admin", true) == 0 ) 
   return GroupId == 1; 
  else 
   return GroupId > 0; 
 } 
 
 #endregion 
}</pre><p>注意:表示用户信息的类型并不要求一定要实现IPrincipal接口,如果不需要用户组的判断,可以不实现这个接口。</p>
<p>登录时需要调用的方法(定义在MyFormsPrincipal类型中):</p>
<p class="jb51code"><br></p><pre class="brush:csharp;">/// <summary> 
/// 执行用户登录操作 
/// </summary> 
/// <param name="loginName">登录名</param> 
/// <param name="userData">与登录名相关的用户信息</param> 
/// <param name="expiration">登录Cookie的过期时间,单位:分钟。</param> 
public static void SignIn(string loginName, TUserData userData, int expiration) 
{ 
 if( string.IsNullOrEmpty(loginName) ) 
  throw new ArgumentNullException("loginName"); 
 if( userData == null ) 
  throw new ArgumentNullException("userData"); 
 
 // 1. 把需要保存的用户数据转成一个字符串。 
 string data = null; 
 if( userData != null ) 
  data = (new JavaScriptSerializer()).Serialize(userData); 
 
 
 // 2. 创建一个FormsAuthenticationTicket,它包含登录名以及额外的用户数据。 
 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket( 
  2, loginName, DateTime.Now, DateTime.Now.AddDays(1), true, data); 
 
 
 // 3. 加密Ticket,变成一个加密的字符串。 
 string cookieValue = FormsAuthentication.Encrypt(ticket); 
 
 
 // 4. 根据加密结果创建登录Cookie 
 HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue); 
 cookie.HttpOnly = true; 
 cookie.Secure = FormsAuthentication.RequireSSL; 
 cookie.Domain = FormsAuthentication.CookieDomain; 
 cookie.Path = FormsAuthentication.FormsCookiePath; 
 if( expiration > 0 ) 
  cookie.Expires = DateTime.Now.AddMinutes(expiration); 
 
 HttpContext context = HttpContext.Current; 
 if( context == null ) 
  throw new InvalidOperationException(); 
 
 // 5. 写登录Cookie 
 context.Response.Cookies.Remove(cookie.Name); 
 context.Response.Cookies.Add(cookie); 
}</pre><p>这里有必要再补充一下:登录状态是有过期限制的。Cookie有 有效期,FormsAuthenticationTicket对象也有 有效期。这二者任何一个过期时,都将导致登录状态无效。按照默认设置,FormsAuthenticationModule将采用slidingExpiration=true的策略来处理FormsAuthenticationTicket过期问题。</p>
<p>登录页面代码:</p>
<p class="jb51code"><br></p><pre class="brush:php;toolbar:false"><fieldset><legend>包含【用户信息】的自定义登录</legend> <form action="<%= Request.RawUrl %>" method="post"> 
 <table border="0"> 
 <tr><td>登录名:</td> 
  <td><input type="text" name="loginName" style="width: 200px" value="Fish" /></td></tr> 
 <tr><td>UserId:</td> 
  <td><input type="text" name="UserId" style="width: 200px" value="78" /></td></tr> 
 <tr><td>GroupId:</td> 
  <td><input type="text" name="GroupId" style="width: 200px" /> 
  1表示管理员用户 
  </td></tr> 
 <tr><td>用户全名:</td> 
  <td><input type="text" name="UserName" style="width: 200px" value="Fish Li" /></td></tr> 
 </table>  
 <input type="submit" name="CustomizeLogin" value="登录" /> 
</form></fieldset></pre><p>登录处理代码:</p>
<p class="jb51code"><br></p><pre class="brush:csharp;">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(); 
}</pre><p>显示用户信息的页面代码:</p>
<p class="jb51code"><br></p><pre class="brush:php;toolbar:false"><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" name="Logon" value="退出" /> 
 <% } else { %> 
  <b>当前用户还未登录。</b> 
 <% } %>    
</form></fieldset></pre><p>为了能让上面的页面代码发挥工作,必须在页面显示前重新设置HttpContext.User对象。<br>为此,我在Global.asax中添加了一个事件处理器:</p>
<p class="jb51code"><br></p><pre class="brush:php;toolbar:false">protected void Application_AuthenticateRequest(object sender, EventArgs e) 
{ 
 HttpApplication app = (HttpApplication)sender; 
 MyFormsPrincipal<UserInfo>.TrySetUserInfo(app.Context); 
} 
TrySetUserInfo的实现代码:

/// <summary> 
/// 根据HttpContext对象设置用户标识对象 
/// </summary> 
/// <param name="context"></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 { /* 有异常也不要抛出,防止攻击者试探。 */ } 
}</pre><p>在多台服务器之间使用Forms身份认证</p>
<p>默认情况下,ASP.NET 生成随机密钥并将其存储在本地安全机构 (LSA) 中,因此,当需要在多台机器之间使用Forms身份认证时,就不能再使用随机生成密钥的方式, 需要我们手工指定,保证每台机器的密钥是一致的。</p>
<p>用于Forms身份认证的密钥可以在web.config的machineKey配置节中指定,我们还可以指定加密解密算法:</p>
<p class="jb51code"><br></p><pre class="brush:php;toolbar:false"><machineKey 
 decryption="Auto" [Auto | DES | 3DES | AES] 
 decryptionKey="AutoGenerate,IsolateApps" [String] 
/></pre><p>关于这二个属性,MSDN有如下解释:</p>
<p style="text-align: center"> <img id="theimg" alt="ASP.NET Forms身份认证详解" src="https://img.php.cn/upload/article/000/000/013/84923e8286a7c50e92daabf1999cff90-7.png"    style="max-width:90%"  style="max-width:90%" title="ASP.NET Forms身份认证详解"></p>
<p>在客户端程序中访问受限页面<br>这一小节送给所有对自动化测试感兴趣的朋友。</p>
<p>有时我们需要用代码访问某些页面,比如:希望用代码测试服务端的响应。</p>
<p>如果是简单的页面,或者页面允许所有客户端访问,这样不会有问题,但是,如果此时我们要访问的页面是一个受限页面,那么就必须也要像人工操作那样:先访问登录页面,提交登录数据,获取服务端生成的登录Cookie,接下来才能去访问其它的受限页面(但要带上登录Cookie)。</p>
<p>注意:由于登录Cookie通常是加密的,且会发生变化,因此直接在代码中硬编码指定登录Cookie会导致代码难以维护。</p>
<p>在前面的示例中,我已在web.config为MyInfo.aspx设置过禁止匿名访问,如果我用下面的代码去调用:</p>
<p class="jb51code"><br></p><pre class="brush:csharp;">private static readonly string MyInfoPageUrl = "http://localhost:51855/MyInfo.aspx"; 
 
static void Main(string[] args) 
{ 
 // 这个调用得到的结果其实是default.aspx页面的输出,并非MyInfo.aspx 
 HttpWebRequest request = MyHttpClient.CreateHttpWebRequest(MyInfoPageUrl); 
 string html = MyHttpClient.GetResponseText(request); 
 
 if( html.IndexOf("<span>Fish</span>") > 0 ) 
  Console.WriteLine("调用成功。"); 
 else 
  Console.WriteLine("页面结果不符合预期。"); 
}</pre><p>此时,输出的结果将会是:</p>
<p>页面结果不符合预期。</p>
<p>如果我用下面的代码:</p>
<p class="jb51code"><br></p><pre class="brush:csharp;">private static readonly string LoginUrl = "http://localhost:51855/default.aspx"; 
private static readonly string MyInfoPageUrl = "http://localhost:51855/MyInfo.aspx"; 
 
static void Main(string[] args) 
{ 
 // 创建一个CookieContainer实例,供多次请求之间共享Cookie 
 CookieContainer cookieContainer = new CookieContainer(); 
 
 // 首先去登录页面登录 
 MyHttpClient.HttpPost(LoginUrl, "NormalLogin=aa&loginName=Fish", cookieContainer); 
 
 // 此时cookieContainer已经包含了服务端生成的登录Cookie 
 
 // 再去访问要请求的页面。 
 string html = MyHttpClient.HttpGet(MyInfoPageUrl, cookieContainer); 
 
 if( html.IndexOf("<span>Fish</span>") > 0 ) 
  Console.WriteLine("调用成功。"); 
 else 
  Console.WriteLine("页面结果不符合预期。"); 
 
 // 如果还要访问其它的受限页面,可以继续调用。 
}</pre><p>此时,输出的结果将会是:</p>
<p>调用成功。</p>
<p>说明:在改进的版本中,我首先创建一个CookieContainer实例,它可以在HTTP调用过程中接收服务器产生的Cookie,并能在发送HTTP请求时将已经保存的Cookie再发送给服务端。在创建好CookieContainer实例之后,每次使用HttpWebRequest对象时,只要将CookieContainer实例赋值给HttpWebRequest对象的CookieContainer属性,即可实现在多次的HTTP调用中Cookie的接收与发送,最终可以模拟浏览器的Cookie处理行为,服务端也能正确识别客户的身份。</p>
<p>ASP.NET Forms身份认证就说到这里,如果您对ASP.NET Windows身份认证有兴趣,那么请继续关注相关文章。</p>
<p>更多ASP.NET Forms身份认证详解相关文章请关注PHP中文网!</p>					</div>
					<div class="artmoreart ">
													<div class="artdp artptit"><span></span>
								<p>相关文章</p>
							</div>
							<div class="artmores flexColumn">
																	<a class="artmrlis flexRow" href="/faq/1829929.html" title="C#如何实现JWT(JSON Web Token)认证?ASP.NET Core Web API安全入门"><b></b>
										<p class="overflowclass">C#如何实现JWT(JSON Web Token)认证?ASP.NET Core Web API安全入门</p>
									</a>
																	<a class="artmrlis flexRow" href="/faq/1747731.html" title=".NET中的JWT认证是什么?如何在Web API中实现Token验证?"><b></b>
										<p class="overflowclass">.NET中的JWT认证是什么?如何在Web API中实现Token验证?</p>
									</a>
																	<a class="artmrlis flexRow" href="/faq/1733917.html" title=".NET中的身份认证(Authentication)与授权(Authorization)是什么?如何使用Identity框架?"><b></b>
										<p class="overflowclass">.NET中的身份认证(Authentication)与授权(Authorization)是什么?如何使用Identity框架?</p>
									</a>
																	<a class="artmrlis flexRow" href="/faq/1685835.html" title=".NET Web API如何实现JWT用户认证_JWT认证实现完整流程"><b></b>
										<p class="overflowclass">.NET Web API如何实现JWT用户认证_JWT认证实现完整流程</p>
									</a>
																	<a class="artmrlis flexRow" href="/faq/1676560.html" title=".NET Web API如何实现身份验证和授权"><b></b>
										<p class="overflowclass">.NET Web API如何实现身份验证和授权</p>
									</a>
															</div>
						
						<p class="statement">本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn</p>
						<div class="lastanext flexRow">
													<a class="lastart flexRow" href="/faq/351529.html" title="ASP.NET Forms身份认证"><span>上一篇:</span>ASP.NET Forms身份认证</a>
													<a class="nextart flexRow" href="/faq/351531.html" title="asp.net实现服务器文件下载到本地的方法"><span>下一篇:</span>asp.net实现服务器文件下载到本地的方法</a>
												</div>
					</div>

					<div class="artlef-down ">
													<div class="authormore ">
								<div class="rightdTitle flexRow">
									<div class="title-left flexRow"> <b></b>
										<p>作者最新文章</p>
									</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/338018.html" title="实现一个 Java 版的 Redis"><b></b>
												<p class="overflowclass">实现一个 Java 版的 Redis</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-30 13:56</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/346502.html" title="Asp.net使用SignalR实现发送图片"><b></b>
												<p class="overflowclass">Asp.net使用SignalR实现发送图片</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-28 16:22</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/350853.html" title="HTML5:使用Canvas实时处理Video"><b></b>
												<p class="overflowclass">HTML5:使用Canvas实时处理Video</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-28 17:58</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/353509.html" title="最简单的微信小程序Demo"><b></b>
												<p class="overflowclass">最简单的微信小程序Demo</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-30 10:20</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/354423.html" title="Python构造自定义方法来美化字典结构输出"><b></b>
												<p class="overflowclass">Python构造自定义方法来美化字典结构输出</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-29 10:33</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/354750.html" title="html设置加粗、倾斜、下划线、删除线等字体效果示例介绍"><b></b>
												<p class="overflowclass">html设置加粗、倾斜、下划线、删除线等字体效果示例介绍</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-31 09:48</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/354839.html" title=" 微信小程序:如何实现tabs选项卡效果示例"><b></b>
												<p class="overflowclass"> 微信小程序:如何实现tabs选项卡效果示例</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-29 15:01</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/354842.html" title="微信小程序开发教程-App()和Page()函数概述"><b></b>
												<p class="overflowclass">微信小程序开发教程-App()和Page()函数概述</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-28 16:19</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/356272.html" title="python中pandas.DataFrame(创建、索引、增添与删除)的简单操作方法介绍"><b></b>
												<p class="overflowclass">python中pandas.DataFrame(创建、索引、增添与删除)的简单操作方法介绍</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-29 15:23</p>
											</div>
										</div>
								</div>
																	<div class="authlist flexColumn">
										<div class="autharts flexRow">
											<a class="autharta flexRow " href="/faq/356574.html" title="详解python redis使用方法"><b></b>
												<p class="overflowclass">详解python redis使用方法</p>
											</a>
											<div class="authtime flexRow"><b></b>
												<p>2018-05-28 15:01</p>
											</div>
										</div>
								</div>
															</div>
						
						<div class="moreAi ">
							<div class="rightdTitle flexRow">
								<div class="title-left flexRow"> <b></b>
									<p>热门AI工具</p>
								</div>
								<a target="_blank" class="rititle-more flexRow" href="/ai" title="热门AI工具"><span>更多</span><b></b></a>
							</div>

							<div class="moreailist flexRow">
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/723" title="DeepSeek" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/000/000/000/175679963982777.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="DeepSeek" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">DeepSeek</p>
												<p class="overflowclass abriptwo">幻方量化公司旗下的开源大模型平台</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/code/large-model" title="AI大模型" class="aidcontbp flexRow flexcenter">AI大模型</p>
																													<p href="/ai/tag/code/open-plat" title="开放平台" class="aidcontbp flexRow flexcenter">开放平台</p>
																											</div>
																							</div>
										</a>
									</div>
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/726" title="豆包大模型" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/000/000/000/175680204067325.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="豆包大模型" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">豆包大模型</p>
												<p class="overflowclass abriptwo">字节跳动自主研发的一系列大型语言模型</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/code/large-model" title="AI大模型" class="aidcontbp flexRow flexcenter">AI大模型</p>
																											</div>
																							</div>
										</a>
									</div>
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/725" title="通义千问" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/000/000/000/175679974228210.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="通义千问" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">通义千问</p>
												<p class="overflowclass abriptwo">阿里巴巴推出的全能AI助手</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/code/large-model" title="AI大模型" class="aidcontbp flexRow flexcenter">AI大模型</p>
																											</div>
																							</div>
										</a>
									</div>
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/854" title="腾讯元宝" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/000/000/000/175679978251103.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="腾讯元宝" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">腾讯元宝</p>
												<p class="overflowclass abriptwo">腾讯混元平台推出的AI助手</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/office/docs" title="文档处理" class="aidcontbp flexRow flexcenter">文档处理</p>
																													<p href="/ai/tag/office/excel" title="Excel 表格" class="aidcontbp flexRow flexcenter">Excel 表格</p>
																											</div>
																							</div>
										</a>
									</div>
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/724" title="文心一言" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/000/000/000/175679974557049.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="文心一言" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">文心一言</p>
												<p class="overflowclass abriptwo">文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/code/large-model" title="AI大模型" class="aidcontbp flexRow flexcenter">AI大模型</p>
																													<p href="/ai/tag/text/chinese-writing" title="中文写作" class="aidcontbp flexRow flexcenter">中文写作</p>
																											</div>
																							</div>
										</a>
									</div>
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/1507" title="讯飞写作" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/000/969/633/68b7a4153cd86671.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="讯飞写作" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">讯飞写作</p>
												<p class="overflowclass abriptwo">基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/text/chinese-writing" title="中文写作" class="aidcontbp flexRow flexcenter">中文写作</p>
																													<p href="/ai/tag/text/write" title="写作工具" class="aidcontbp flexRow flexcenter">写作工具</p>
																											</div>
																							</div>
										</a>
									</div>
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/1115" title="即梦AI" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/001/246/273/68b6d8f7c530c315.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="即梦AI" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">即梦AI</p>
												<p class="overflowclass abriptwo">一站式AI创作平台,免费AI图片和视频生成。</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/image/image-titching" title="图片拼接" class="aidcontbp flexRow flexcenter">图片拼接</p>
																													<p href="/ai/tag/image/image-create" title="图画生成" class="aidcontbp flexRow flexcenter">图画生成</p>
																											</div>
																							</div>
										</a>
									</div>
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/808" title="ChatGPT" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/000/000/000/175679970194596.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="ChatGPT" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">ChatGPT</p>
												<p class="overflowclass abriptwo">最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/code/large-model" title="AI大模型" class="aidcontbp flexRow flexcenter">AI大模型</p>
																													<p href="/ai/tag/text/chinese-writing" title="中文写作" class="aidcontbp flexRow flexcenter">中文写作</p>
																											</div>
																							</div>
										</a>
									</div>
																	<div class="aidcons flexRow  check ">
										<a target="_blank" href="/ai/821" title="智谱清言 - 免费全能的AI助手" class="aibtns flexRow">
											<img src="https://img.php.cn/upload/ai_manual/000/000/000/175679976181507.png?x-oss-process=image/resize,m_mfit,h_70,w_70,limit_0" alt="智谱清言 - 免费全能的AI助手" class="aibtnimg"
												onerror="this.src='/static/lhimages/moren/morentu.png'">
											<div class="aibtn-right flexColumn">
												<p class="overflowclass abripone">智谱清言 - 免费全能的AI助手</p>
												<p class="overflowclass abriptwo">智谱清言 - 免费全能的AI助手</p>
																									<div class="aidconstab flexRow">
																												<p href="/ai/tag/code/large-model" title="AI大模型" class="aidcontbp flexRow flexcenter">AI大模型</p>
																													<p href="/ai/tag/office/pdf" title="PDF 文档" class="aidcontbp flexRow flexcenter">PDF 文档</p>
																											</div>
																							</div>
										</a>
									</div>
															</div>




						</div>

					</div>


				</div>


			</div>
			<div class="conRight artdtilRight ">
				<div class="artrig-adv ">
                    <script type="text/javascript" src="https://teacher.php.cn/php/MDM3MTk1MGYxYjI5ODJmNTE0ZWVkZTA3NmJhYzhmMjI6Og=="></script>
                </div>
				<div class="hotzt artdtzt">
					<div class="rightdTitle flexRow">
						<div class="title-left flexRow"> <b></b>
							<p>相关专题</p>
						</div>
						<a target="_blank" class="rititle-more flexRow" href="/faq/zt" title="相关专题"><span>更多</span><b></b></a>
					</div>
					<div class="hotztuls flexColumn">
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/phpymazjcdq" class="aClass flexRow hotzta" title="php源码安装教程大全"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123115154686243.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="php源码安装教程大全" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/phpymazjcdq" class="aClass flexRow hotztra overflowclass" title="php源码安装教程大全">php源码安装教程大全</a>
									<p class="aClass flexRow hotztrp overflowclass">本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">7</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/phpwzymjcdq" class="aClass flexRow hotzta" title="php网站源码教程大全"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123115111986288.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="php网站源码教程大全" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/phpwzymjcdq" class="aClass flexRow hotztra overflowclass" title="php网站源码教程大全">php网站源码教程大全</a>
									<p class="aClass flexRow hotztrp overflowclass">本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">4</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/spwjgs" class="aClass flexRow hotzta" title="视频文件格式"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123114550378407.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="视频文件格式" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/spwjgs" class="aClass flexRow hotztra overflowclass" title="视频文件格式">视频文件格式</a>
									<p class="aClass flexRow hotztrp overflowclass">本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">7</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/bsgnxzdllqdq" class="aClass flexRow hotzta" title="不受国内限制的浏览器大全"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123114463515249.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="不受国内限制的浏览器大全" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/bsgnxzdllqdq" class="aClass flexRow hotztra overflowclass" title="不受国内限制的浏览器大全">不受国内限制的浏览器大全</a>
									<p class="aClass flexRow hotztrp overflowclass">想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">7</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/cxslsjjffdq" class="aClass flexRow hotzta" title="出现404解决方法大全"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123114400177727.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="出现404解决方法大全" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/cxslsjjffdq" class="aClass flexRow hotztra overflowclass" title="出现404解决方法大全">出现404解决方法大全</a>
									<p class="aClass flexRow hotztrp overflowclass">本专题整合了404错误解决方法大全,阅读专题下面的文章了解更多详细内容。</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">42</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/html5zmbfsp" class="aClass flexRow hotzta" title="html5怎么播放视频"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123114321313861.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="html5怎么播放视频" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/html5zmbfsp" class="aClass flexRow hotztra overflowclass" title="html5怎么播放视频">html5怎么播放视频</a>
									<p class="aClass flexRow hotztrp overflowclass">想让网页流畅播放视频?本合集详解HTML5视频播放核心方法!涵盖<video>标签基础用法、多格式兼容(MP4/WebM/OGV)、自定义播放控件、响应式适配及常见浏览器兼容问题解决方案。无需插件,纯前端实现高清视频嵌入,助你快速打造现代化网页视频体验。</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">4</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/gbwinxtzdgxjc" class="aClass flexRow hotzta" title="关闭win10系统自动更新教程大全"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123114222331548.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="关闭win10系统自动更新教程大全" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/gbwinxtzdgxjc" class="aClass flexRow hotztra overflowclass" title="关闭win10系统自动更新教程大全">关闭win10系统自动更新教程大全</a>
									<p class="aClass flexRow hotztrp overflowclass">本专题整合了关闭win10系统自动更新教程大全,阅读专题下面的文章了解更多详细内容。</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">3</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/zzdnzdazrjjc" class="aClass flexRow hotzta" title="阻止电脑自动安装软件教程"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123114132289798.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="阻止电脑自动安装软件教程" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/zzdnzdazrjjc" class="aClass flexRow hotztra overflowclass" title="阻止电脑自动安装软件教程">阻止电脑自动安装软件教程</a>
									<p class="aClass flexRow hotztrp overflowclass">本专题整合了阻止电脑自动安装软件教程,阅读专题下面的文章了解更多详细教程。</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">3</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
													<div class="hotztlls flexRow">
								<a target="_blank" href="/faq/html5zmsy" class="aClass flexRow hotzta" title="html5怎么使用"><img
										src="https://img.php.cn/upload/subject/202512/31/2025123114112079655.jpg?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="html5怎么使用" class="hotztaimg"
										onerror="this.src='/static/lhimages/moren/morentu.png'"></a>
								<div class="hotztright flexColumn">
									<a target="_blank" href="/faq/html5zmsy" class="aClass flexRow hotztra overflowclass" title="html5怎么使用">html5怎么使用</a>
									<p class="aClass flexRow hotztrp overflowclass">想快速上手HTML5开发?本合集为你整理最实用的HTML5使用指南!涵盖HTML5基础语法、主流框架(如Bootstrap、Vue、React)集成方法,以及无需安装、直接在线编辑运行的平台推荐(如CodePen、JSFiddle)。无论你是新手还是进阶开发者,都能轻松掌握HTML5网页制作、响应式布局与交互功能开发,零配置开启高效前端编程之旅!</p>
									<div class="hotztrdown flexRow">
										<div class="htztdsee flexRow"> <b></b>
											<p class="">2</p>
										</div>
										<div class="htztdTime flexRow"> <b></b>
											<p>2025.12.31</p>
										</div>
									</div>
								</div>
							</div>
											</div>
				</div>

				<div class="hotdownload ">
					<div class="rightdTitle flexRow">
						<div class="title-left flexRow"> <b></b>
							<p>热门下载</p>
						</div>
						<a target="_blank" class="rititle-more flexRow" href="/xiazai" title="热门下载"><span>更多</span><b></b></a>
					</div>
					<div class="hotdownTab">
						<div class="hdTabs flexRow">
							<div class="check" data-id="onef">网站特效 <b></b> </div> /
							<div class="" data-id="twof">网站源码 <b></b></div> /
							<div class="" data-id="threef">网站素材 <b></b></div> /
							<div class="" data-id="fourf">前端模板 <b></b></div>
						</div>
						<ul class="onef">
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="仿商城楼层锚点页面滚动代码" href="/xiazai/js/8202"><span>[窗口特效]</span><span>仿商城楼层锚点页面滚动代码</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="CSS3用户登录表单代码" href="/xiazai/js/8201"><span>[表单按钮]</span><span>CSS3用户登录表单代码</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="jquery文章内容阅读全文查看代码" href="/xiazai/js/8200"><span>[文字特效]</span><span>jquery文章内容阅读全文查看代码</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="图片弹出imgCentering插件" href="/xiazai/js/8199"><span>[图片特效]</span><span>图片弹出imgCentering插件</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="黑色的固定导航下拉菜单ui布局" href="/xiazai/js/8198"><span>[菜单导航]</span><span>黑色的固定导航下拉菜单ui布局</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="CSS3星球旋转手机表单代码" href="/xiazai/js/8197"><span>[表单按钮]</span><span>CSS3星球旋转手机表单代码</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="炫酷的程序员个人简历文字动画代码" href="/xiazai/js/8196"><span>[文字特效]</span><span>炫酷的程序员个人简历文字动画代码</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="网页文章索引导航预览特效" href="/xiazai/js/8195"><span>[菜单导航]</span><span>网页文章索引导航预览特效</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="保障险产品列表3D翻转布局" href="/xiazai/js/8194"><span>[窗口特效]</span><span>保障险产品列表3D翻转布局</span></a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" title="HTML5 SVG液态表单动画特效" href="/xiazai/js/8193"><span>[表单按钮]</span><span>HTML5 SVG液态表单动画特效</span></a>
									</div>
								</li>
													</ul>
						<ul class="twof" style="display:none;">
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11353" title="雅龙智能装备工业设备类WordPress主题1.0"><span>[企业站源码]</span><span>雅龙智能装备工业设备类WordPress主题1.0</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11352" title="威发卡自动发卡系统"><span>[电商源码]</span><span>威发卡自动发卡系统</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11351" title="卡密分发系统"><span>[电商源码]</span><span>卡密分发系统</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11350" title="中华陶瓷网"><span>[电商源码]</span><span>中华陶瓷网</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11349" title="简洁粉色食品公司网站"><span>[电商源码]</span><span>简洁粉色食品公司网站</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11348" title="极速网店系统"><span>[电商源码]</span><span>极速网店系统</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11347" title="淘宝妈妈_淘客推广系统"><span>[电商源码]</span><span>淘宝妈妈_淘客推广系统</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11346" title="积客B2SCMS商城系统"><span>[电商源码]</span><span>积客B2SCMS商城系统</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11345" title="CODEC2I 众筹系统"><span>[电商源码]</span><span>CODEC2I 众筹系统</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/11344" title="ieshop超级网店系统"><span>[电商源码]</span><span>ieshop超级网店系统</span> </a>
									</div>
								</li>
													</ul>
						<ul class="threef" style="display:none;">
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4143" title="2026新年加载进度条矢量图片"><span>[网站素材]</span><span>2026新年加载进度条矢量图片</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4142" title="创意工作室营业海报设计素材下载"><span>[网站素材]</span><span>创意工作室营业海报设计素材下载</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4141" title="国潮中式锦鲤荷塘矢量背景"><span>[网站素材]</span><span>国潮中式锦鲤荷塘矢量背景</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4140" title="复古红色咖啡促销海报矢量模板"><span>[网站素材]</span><span>复古红色咖啡促销海报矢量模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4139" title="2026新年快乐竖版海报PSD模板设计下载"><span>[网站素材]</span><span>2026新年快乐竖版海报PSD模板设计下载</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4138" title="孟菲斯几何2026新年贺卡矢量"><span>[网站素材]</span><span>孟菲斯几何2026新年贺卡矢量</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4137" title="珠宝饰品折扣感谢卡ps素材下载"><span>[网站素材]</span><span>珠宝饰品折扣感谢卡ps素材下载</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4136" title="2026新年创意剪影海报矢量素材"><span>[网站素材]</span><span>2026新年创意剪影海报矢量素材</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4135" title="极简线条女子美容护肤矢量素材"><span>[网站素材]</span><span>极简线条女子美容护肤矢量素材</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/sucai/4134" title="2026年日历表设计源文件下载"><span>[网站素材]</span><span>2026年日历表设计源文件下载</span> </a>
									</div>
								</li>
													</ul>
						<ul class="fourf" style="display:none;">
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8590"  title="驾照考试驾校HTML5网站模板"><span>[前端模板]</span><span>驾照考试驾校HTML5网站模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8589"  title="驾照培训服务机构宣传网站模板"><span>[前端模板]</span><span>驾照培训服务机构宣传网站模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8588"  title="HTML5房地产公司宣传网站模板"><span>[前端模板]</span><span>HTML5房地产公司宣传网站模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8587"  title="新鲜有机肉类宣传网站模板"><span>[前端模板]</span><span>新鲜有机肉类宣传网站模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8586"  title="响应式天气预报宣传网站模板"><span>[前端模板]</span><span>响应式天气预报宣传网站模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8585"  title="房屋建筑维修公司网站CSS模板"><span>[前端模板]</span><span>房屋建筑维修公司网站CSS模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8584"  title="响应式志愿者服务网站模板"><span>[前端模板]</span><span>响应式志愿者服务网站模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8583"  title="创意T恤打印店网站HTML5模板"><span>[前端模板]</span><span>创意T恤打印店网站HTML5模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8582"  title="网页开发岗位简历作品展示网页模板"><span>[前端模板]</span><span>网页开发岗位简历作品展示网页模板</span> </a>
									</div>
								</li>
															<li>
									<div class="wzrfourli flexRow">
										<b></b>
										<a target="_blank" href="/xiazai/code/8581"  title="响应式人力资源机构宣传网站模板"><span>[前端模板]</span><span>响应式人力资源机构宣传网站模板</span> </a>
									</div>
								</li>
													</ul>
					</div>
					<script>
						$('.hdTabs>div').click(function (e) {
							$('.hdTabs>div').removeClass('check')
							$(this).addClass('check')
							$('.hotdownTab>ul').css('display', 'none')
							$('.' + e.currentTarget.dataset.id).show()
						})
					</script>

				</div>

				<div class="artrig-adv ">
					<script type="text/javascript" src="https://teacher.php.cn/php/MDM3MTk1MGYxYjI5ODJmNTE0ZWVkZTA3NmJhYzhmMjI6Og=="></script>
                </div>



				<div class="xgarts ">
					<div class="rightdTitle flexRow">
						<div class="title-left flexRow"> <b></b>
							<p>相关下载</p>
						</div>
						<a target="_blank" class="rititle-more flexRow" href="/xiazai" title="相关下载"><span>更多</span><b></b></a>
					</div>
					<div class="xgwzlist ">
											<div class="xgwzlid flexRow"><b></b><a target="_blank" title="php商城系统" href="/xiazai/code/11178">php商城系统</a></div>
											<div class="xgwzlid flexRow"><b></b><a target="_blank" title="淘源码商城PHP淘宝查信誉" href="/xiazai/code/11177">淘源码商城PHP淘宝查信誉</a></div>
											<div class="xgwzlid flexRow"><b></b><a target="_blank" title="PHP房产程序[BBWPS]" href="/xiazai/code/11165">PHP房产程序[BBWPS]</a></div>
											<div class="xgwzlid flexRow"><b></b><a target="_blank" title="PHP简约自动发卡平台个人版" href="/xiazai/code/11128">PHP简约自动发卡平台个人版</a></div>
											<div class="xgwzlid flexRow"><b></b><a target="_blank" title="ERMEB域名PHP离线网络授权系统" href="/xiazai/code/11040">ERMEB域名PHP离线网络授权系统</a></div>
											<div class="xgwzlid flexRow"><b></b><a target="_blank" title="Difeye-敏捷的轻量级PHP框架" href="/xiazai/code/11037">Difeye-敏捷的轻量级PHP框架</a></div>
											<div class="xgwzlid flexRow"><b></b><a target="_blank" title="大泉州汽车网PHP整站程序" href="/xiazai/code/10963">大泉州汽车网PHP整站程序</a></div>
										</div>

				</div>

				<div class="jpkc">
					<div class="rightdTitle flexRow">
						<div class="title-left flexRow"> <b></b>
							<p>精品课程</p>
						</div>
						<a class="rititle-more flexRow" target="_blank" href="/course/sort_new.html" title="精品课程"><span>更多</span><b></b></a>
					</div>
					<div class=" jpkcTab">
						<div class=" jpkcTabs flexRow">
							<div class="check" data-id="onefd">相关推荐 <b></b> </div> /
							<div class="" data-id="twofd">热门推荐 <b></b></div> /
							<div class="" data-id="threefd">最新课程 <b></b></div>
						</div>
						<div class="onefd jpktabd">
													<div  class="ristyA flexRow " >
								<a target="_blank" href="/course/284.html" title="极客学院ASP.NET视频教程">
									<img src="https://img.php.cn/upload/course/000/000/068/625685fee1faa301.png?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="极客学院ASP.NET视频教程" class="ristyAimg"
										onerror="this.src='/static/mobimages/moren/morentu.png'">
								</a>
								<div class="ristyaRight flexColumn">
									<a target="_blank" href="/course/284.html" title="极客学院ASP.NET视频教程"
										class="rirightp overflowclass">极客学院ASP.NET视频教程</a>

									<div class="risrdown flexRow">
										<p>共90课时 | 20.3万人学习</p>
									</div>
								</div>
							</div>
													<div  class="ristyA flexRow " >
								<a target="_blank" href="/course/1379.html" title="Node.js全套入门教程【es6+npm+express+webpack+promise】">
									<img src="https://img.php.cn/upload/course/000/000/068/6242b4c8f1a39624.png?x-oss-process=image/resize,m_mfit,h_75,w_120,limit_0" alt="Node.js全套入门教程【es6+npm+express+webpack+promise】" class="ristyAimg"
										onerror="this.src='/static/mobimages/moren/morentu.png'">
								</a>
								<div class="ristyaRight flexColumn">
									<a target="_blank" href="/course/1379.html" title="Node.js全套入门教程【es6+npm+express+webpack+promise】"
										class="rirightp overflowclass">Node.js全套入门教程【es6+npm+express+webpack+promise】</a>

									<div class="risrdown flexRow">
										<p>共96课时 | 13万人学习</p>
									</div>
								</div>
							</div>
												</div>

						<div class="twofd jpktabd" style="display:none;">
															<div  class="ristyA flexRow " >
									<a target="_blank" href="/course/1656.html" title="JavaScript ES5基础线上课程教学">
										<img src="https://img.php.cn/upload/course/000/000/081/6862652adafef801.png?x-oss-process=image/resize,m_mfit,h_86,w_140,limit_0" alt="JavaScript ES5基础线上课程教学" class="ristyAimg"
											onerror="this.src='/static/mobimages/moren/morentu.png'">
									</a>
									<div class="ristyaRight flexColumn">
										<a target="_blank" href="/course/1656.html" title="JavaScript ES5基础线上课程教学"
											class="rirightp overflowclass">JavaScript ES5基础线上课程教学</a>

										<div class="risrdown flexRow">
											<p>共6课时 | 6.9万人学习</p>
										</div>
									</div>
								</div>
															<div  class="ristyA flexRow " >
									<a target="_blank" href="/course/812.html" title="最新ThinkPHP 5.1全球首发视频教程(60天成就PHP大牛线上培训班课)">
										<img src="https://img.php.cn/upload/course/000/000/041/620debc3eab3f377.jpg?x-oss-process=image/resize,m_mfit,h_86,w_140,limit_0" alt="最新ThinkPHP 5.1全球首发视频教程(60天成就PHP大牛线上培训班课)" class="ristyAimg"
											onerror="this.src='/static/mobimages/moren/morentu.png'">
									</a>
									<div class="ristyaRight flexColumn">
										<a target="_blank" href="/course/812.html" title="最新ThinkPHP 5.1全球首发视频教程(60天成就PHP大牛线上培训班课)"
											class="rirightp overflowclass">最新ThinkPHP 5.1全球首发视频教程(60天成就PHP大牛线上培训班课)</a>

										<div class="risrdown flexRow">
											<p>共79课时 | 150.7万人学习</p>
										</div>
									</div>
								</div>
															<div  class="ristyA flexRow " >
									<a target="_blank" href="/course/639.html" title="phpStudy极速入门视频教程">
										<img src="https://img.php.cn/upload/course/000/000/068/62611ef88fcec821.jpg?x-oss-process=image/resize,m_mfit,h_86,w_140,limit_0" alt="phpStudy极速入门视频教程" class="ristyAimg"
											onerror="this.src='/static/mobimages/moren/morentu.png'">
									</a>
									<div class="ristyaRight flexColumn">
										<a target="_blank" href="/course/639.html" title="phpStudy极速入门视频教程"
											class="rirightp overflowclass">phpStudy极速入门视频教程</a>

										<div class="risrdown flexRow">
											<p>共6课时 | 53.3万人学习</p>
										</div>
									</div>
								</div>
													</div>

						<div class="threefd jpktabd" style="display:none;">
															<div  class="ristyA flexRow " >
										<a target="_blank" href="/course/1696.html" title="最新Python教程 从入门到精通">
											<img src="https://img.php.cn/upload/course/000/000/081/68c135bb72783194.png?x-oss-process=image/resize,m_mfit,h_86,w_140,limit_0" alt="最新Python教程 从入门到精通" class="ristyAimg"
												onerror="this.src='/static/mobimages/moren/morentu.png'">
										</a>
										<div class="ristyaRight flexColumn">
											<a target="_blank" href="/course/1696.html" title="最新Python教程 从入门到精通"
												class="rirightp overflowclass">最新Python教程 从入门到精通</a>

											<div class="risrdown flexRow">
												<p>共4课时 | 0.6万人学习</p>
											</div>
										</div>
									</div>
																<div  class="ristyA flexRow " >
										<a target="_blank" href="/course/1656.html" title="JavaScript ES5基础线上课程教学">
											<img src="https://img.php.cn/upload/course/000/000/081/6862652adafef801.png?x-oss-process=image/resize,m_mfit,h_86,w_140,limit_0" alt="JavaScript ES5基础线上课程教学" class="ristyAimg"
												onerror="this.src='/static/mobimages/moren/morentu.png'">
										</a>
										<div class="ristyaRight flexColumn">
											<a target="_blank" href="/course/1656.html" title="JavaScript ES5基础线上课程教学"
												class="rirightp overflowclass">JavaScript ES5基础线上课程教学</a>

											<div class="risrdown flexRow">
												<p>共6课时 | 6.9万人学习</p>
											</div>
										</div>
									</div>
																<div  class="ristyA flexRow " >
										<a target="_blank" href="/course/1655.html" title="PHP新手语法线上课程教学">
											<img src="https://img.php.cn/upload/course/000/000/081/684a8c23d811b293.png?x-oss-process=image/resize,m_mfit,h_86,w_140,limit_0" alt="PHP新手语法线上课程教学" class="ristyAimg"
												onerror="this.src='/static/mobimages/moren/morentu.png'">
										</a>
										<div class="ristyaRight flexColumn">
											<a target="_blank" href="/course/1655.html" title="PHP新手语法线上课程教学"
												class="rirightp overflowclass">PHP新手语法线上课程教学</a>

											<div class="risrdown flexRow">
												<p>共13课时 | 0.8万人学习</p>
											</div>
										</div>
									</div>
														</div>
						<script>
							$('.jpkcTabs>div').click(function (e) {
								$('.jpkcTabs>div').removeClass('check')
								$(this).addClass('check')
								$('.jpkcTab .jpktabd').css('display', 'none')
								$('.' + e.currentTarget.dataset.id).show()
							})
						</script>

					</div>
				</div>

				<div class="zxarts ">
					<div class="rightdTitle flexRow">
						<div class="title-left flexRow"> <b></b>
							<p>最新文章</p>
						</div>
						<a class="rititle-more flexRow" href="" title="最新文章" target="_blank"><span>更多</span><b></b></a>
					</div>
					<div class="xgwzlist ">
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="c# lock(this) 有什么问题 为什么不能lock this" href="/faq/1913681.html">c# lock(this) 有什么问题 为什么不能lock this</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="C#怎么使用BigInteger C#处理大整数运算方法" href="/faq/1913617.html">C#怎么使用BigInteger C#处理大整数运算方法</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="c# signalr 是什么 怎么用" href="/faq/1913591.html">c# signalr 是什么 怎么用</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="c# 枚举 enum 的用法" href="/faq/1913554.html">c# 枚举 enum 的用法</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="C#如何创建Azure Functions C#编写无服务器函数教程" href="/faq/1913475.html">C#如何创建Azure Functions C#编写无服务器函数教程</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="Avalonia如何实现一个命令栏或工具栏 Avalonia ToolBar" href="/faq/1913470.html">Avalonia如何实现一个命令栏或工具栏 Avalonia ToolBar</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="c# gRPC 和 Web API 在高并发场景下的性能对比" href="/faq/1913447.html">c# gRPC 和 Web API 在高并发场景下的性能对比</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="Blazor 使用 HttpClient 调用 Web API 教程" href="/faq/1913311.html">Blazor 使用 HttpClient 调用 Web API 教程</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="c#和python哪个好学 c#和python怎么选" href="/faq/1913242.html">c#和python哪个好学 c#和python怎么选</a></div>
													<div class="xgwzlid flexRow"><b></b><a target="_blank" title="使用BenchmarkDotNet:精确测量和分析你的.NET代码性能" href="/faq/1913208.html">使用BenchmarkDotNet:精确测量和分析你的.NET代码性能</a></div>
											</div>

				</div>






			</div>



		</div>

	</div>
	<!--底部-->
	<div class="phpFoot">
    <div class="phpFootIn">
        <div class="phpFootCont">
            <div class="phpFootLeft">
                <dl>
                    <dt>
                        <a target="_blank"  href="/about/us.html" rel="nofollow"  title="关于我们" class="cBlack">关于我们</a>
                        <a target="_blank"  href="/about/disclaimer.html" rel="nofollow"  title="免责申明" class="cBlack">免责申明</a>
                        <a target="_blank"  href="/about/jbzx.html" rel="nofollow"  title="举报中心" class="cBlack">举报中心</a>
                        <a   href="javascript:;" rel="nofollow" onclick="advice_data(99999999,'意见反馈')"   title="意见反馈" class="cBlack">意见反馈</a>
                        <a target="_blank"  href="https://www.php.cn/teacher.html" rel="nofollow"   title="讲师合作" class="cBlack">讲师合作</a>
                        <a  target="_blank" href="https://www.php.cn/blog/detail/20304.html" rel="nofollow"  title="广告合作" class="cBlack">广告合作</a>
                        <a  target="_blank" href="/new/"    title="最新文章列表" class="cBlack">最新更新</a>
                                                <div class="clear"></div>
                    </dt>
                    <dd class="cont1">php中文网:公益在线php培训,帮助PHP学习者快速成长!</dd>
                    <dd class="cont2">
                      <span class="ylwTopBox">
                        <a   href="javascript:;"  class="cBlack"><b class="icon1"></b>关注服务号</a>
                        <em style="display:none;" class="ylwTopSub">
                          <p>微信扫码<br/>关注PHP中文网服务号</p>
                          <img src="/static/images/examples/text16.png"/>
                        </em>
                      </span>
                        <span class="ylwTopBox">
                        <a   href="tencent://message/?uin=27220243&Site=www.php.cn&Menu=yes"  class="cBlack"><b class="icon2"></b>技术交流群</a>
                        <em style="display:none;" class="ylwTopSub">
                          <p>QQ扫码<br/>加入技术交流群</p>
                          <img src="/static/images/examples/text18.png"/>
                        </em>
                      </span>
                        <div class="clear"></div>
                    </dd>
                </dl>
                
            </div>
            <div class="phpFootRight">
                <div class="phpFootMsg">
                    <span><img src="/static/images/examples/text17.png"/></span>
                    <dl>
                        <dt>PHP中文网订阅号</dt>
                        <dd>每天精选资源文章推送</dd>
                    </dl>
                </div>
            </div>
        </div>
    </div>
    <div class="phpFootCode">
        <div class="phpFootCodeIn"><p>Copyright 2014-2025 <a   href="https://www.php.cn/" >https://www.php.cn/</a> All Rights Reserved | php.cn | <a   href="https://beian.miit.gov.cn/" rel="nofollow" >湘ICP备2023035733号</a></p><a   href="http://www.beian.gov.cn/portal/index.do" rel="nofollow" ><b></b></a></div>
    </div>
</div>
<input type="hidden" id="verifycode" value="/captcha.html">
<script>
    var _hmt = _hmt || [];
    (function() {
        var hm = document.createElement("script");
        hm.src = "https://hm.baidu.com/hm.js?c0e685c8743351838d2a7db1c49abd56";
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(hm, s);
    })();
</script>
<script>layui.use(['element', 'carousel'], function () {var element = layui.element;$ = layui.jquery;var carousel = layui.carousel;carousel.render({elem: '#test1', width: '100%', height: '330px', arrow: 'always'});$.getScript('/static/js/jquery.lazyload.min.js', function () {$("img").lazyload({placeholder: "/static/images/load.jpg", effect: "fadeIn", threshold: 200, skip_invisible: false});});});</script>

<span class="layui-hide"><script type="text/javascript" src="https://s4.cnzz.com/z_stat.php?id=1280886301&web_id=1280886301"></script></span>

<script src="/static/js/cdn.js?v=1.0.1"></script>



	<!--底部 end-->
	<!-- content -->
	<!--
    <div class="phpFudong">
        <div class="phpFudongIn">
            <div class="phpFudongImg"></div>
            <div class="phpFudongXue">登录PHP中文网,和优秀的人一起学习!</div>
            <div class="phpFudongQuan">全站<span>2000+</span>教程免费学</div>
            <div class="phpFudongCode"><a   href="javascript:;" id="login" title="微信扫码登录">微信扫码登录</a></div>
            <div class="phpGuanbi" onclick="$('.phpFudong').hide();"></div>
            <div class="clear"></div>
        </div>
    </div>
-->	<!--底部浮动层 end-->
	<!--侧导航-->
	<style>
    .layui-fixbar{display: none;}
</style>
<div class="phpSdhBox" style="height:240px !important;">
    <li>
        <div class="phpSdhIn">
            <div class="phpSdhTitle">
                <a   href="/k24.html"  class="hover" title="PHP学习">
                    <b class="icon1"></b>
                    <p>PHP学习</p>
                </a>
            </div>
        </div>
    </li>
    <li>
        <div class="phpSdhIn">
            <div class="phpSdhTitle">
                <a   href="https://www.php.cn/blog/detail/1047189.html" >
                    <b class="icon2"></b>
                    <p>技术支持</p>
                </a>
            </div>
        </div>
    </li>
    <li>
        <div class="phpSdhIn">
            <div class="phpSdhTitle">
                <a   href="#">
                    <b class="icon6"></b>
                    <p>返回顶部</p>
                </a>
            </div>
        </div>
    </li>
</div>
	</body>

</html>

<script type="text/javascript" src="/hitsUp?type=article&id=351530&time=1767186599">
</script>
<script src="/static/ueditor/third-party/SyntaxHighlighter/shCore.js?1767186599"></script>
<script>
	article_status = "13";
</script>
<input type="hidden" id="verifycode" value="/captcha.html">
<script type="text/javascript" src="/static/js/global.min.js?5.5.33"></script>
<link rel='stylesheet' id='_main-css' href='/static/css/viewer.min.css?2' type='text/css' media='all' />
<script type='text/javascript' src='/static/js/viewer.min.js?1'></script>
<script type='text/javascript' src='/static/js/jquery-viewer.min.js'></script>
<script type="text/javascript" src="/static/js/jquery.cookie.js"></script>
<script>var _hmt = _hmt || [];(function(){var hm = document.createElement("script");hm.src="//hm.baidu.com/hm.js?c0e685c8743351838d2a7db1c49abd56";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm, s);})();(function(){var bp = document.createElement('script');var curProtocol = window.location.protocol.split(':')[0];if(curProtocol === 'https'){bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';}else{bp.src = 'http://push.zhanzhang.baidu.com/push.js';};var s = document.getElementsByTagName("script")[0];s.parentNode.insertBefore(bp, s);})();</script>
	

<script>
	function setCookie(name, value, iDay) { //name相当于键,value相当于值,iDay为要设置的过期时间(天)
		var oDate = new Date();
		oDate.setDate(oDate.getDate() + iDay);
		document.cookie = name + '=' + value + ';path=/;domain=.php.cn;expires=' + oDate;
	}

	function getCookie(name) {
		var cookieArr = document.cookie.split(";");
		for (var i = 0; i < cookieArr.length; i++) {
			var cookiePair = cookieArr[i].split("=");
			if (name == cookiePair[0].trim()) {
				return decodeURIComponent(cookiePair[1]);
			}
		}
		return null;
	}
</script>


<!-- Matomo -->
<script>
	var _paq = window._paq = window._paq || [];
	/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
	_paq.push(['trackPageView']);
	_paq.push(['enableLinkTracking']);
	(function () {
		var u = "https://tongji.php.cn/";
		_paq.push(['setTrackerUrl', u + 'matomo.php']);
		_paq.push(['setSiteId', '7']);
		var d = document,
			g = d.createElement('script'),
			s = d.getElementsByTagName('script')[0];
		g.async = true;
		g.src = u + 'matomo.js';
		s.parentNode.insertBefore(g, s);
	})();
</script>
<!-- End Matomo Code -->

<script>
	setCookie('is_article', 1, 1);
</script>

<script>
	var is_login = "0";
        var show = 0;
        var ceng = getCookie('ceng');
        //未登录复制显示登录按钮
        if(is_login == 0 && false){
            $(".code").hover(function(){
                $(this).find('.contentsignin').show();
            },function(){
                $(this).find('.contentsignin').hide();
            });
            //不给复制
            $('.code').bind("cut copy paste",function(e) {
                e.preventDefault();
            });
            $('.code .contentsignin').click(function(){
                $(document).trigger("api.loginpopbox");
            })
        }else{
            // 获取所有的 <pre> 元素
            var preElements = document.querySelectorAll('pre');
            preElements.forEach(function(preElement) {
                // 创建复制按钮
                var copyButton = document.createElement('button');
                copyButton.className = 'copy-button';
                copyButton.textContent = '复制';
                // 添加点击事件处理程序
                copyButton.addEventListener('click', function() {
                    // 获取当前按钮所属的 <pre> 元素中的文本内容
                    var textContent = preElement.textContent.trim();
                    // 创建一个临时 textarea 元素并设置其值为 <pre> 中的文本内容
                    var tempTextarea = document.createElement('textarea');
                    tempTextarea.value = textContent;
                    // 将临时 textarea 添加到文档中
                    document.body.appendChild(tempTextarea);
                    // 选中临时 textarea 中的文本内容并执行复制操作
                    tempTextarea.select();
                    document.execCommand('copy');
                    // 移除临时 textarea 元素
                    document.body.removeChild(tempTextarea);
                    // 更新按钮文本为 "已复制"
                    this.textContent = '已复制';
                });

                // 创建AI写代码按钮
                var aiButton = document.createElement('button');
                aiButton.className = 'copy-button';
                aiButton.textContent = 'AI写代码';
                aiButton.style.marginLeft = '5px';
                aiButton.style.marginRight = '5px';
                // 添加点击事件处理程序
                aiButton.addEventListener('click', function() {
                // Generate a random number between 0 and 1
                        var randomChance = Math.random();

                    // If the random number is less than 0.5, open the first URL, else open the second
                    if (randomChance < 0.5) {
                        window.open('https://www.doubao.com/chat/coding?channel=php&source=hw_db_php', '_blank');
                    } else {
                        window.open('https://click.aliyun.com/m/1000402709/', '_blank');
                    }
                });

                // 将按钮添加到 <pre> 元素前面
                preElement.parentNode.insertBefore(copyButton, preElement);
                preElement.parentNode.insertBefore(aiButton, preElement);
        });
        }
</script>