<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      上篇博客我談到了一些關于ASP.NET Forms身份認證方面的話題,這次的博客將主要介紹ASP.NET Windows身份認證。

      Forms身份認證雖然使用廣泛,不過,如果是在 Windows Active Directory 的環境中使用ASP.NET, 那么使用Windows身份認證也會比較方便。 方便性表現為:我們不用再設計登錄頁面,不用編寫登錄驗證邏輯。而且使用Windows身份認證會有更好的安全保障。

      認識ASP.NET Windows身份認證

      要使用Windows身份認證模式,需要在web.config設置:

      
      <authentication mode="Windows" />
      
      

      Windows身份認證做為ASP.NET的默認認證方式,與Forms身份認證在許多基礎方面是一樣的。 上篇博客我說過:我認為ASP.NET的身份認證的最核心部分其實就是HttpContext.User這個屬性所指向的對象。 在接下來的部分,我將著重分析這個對象在二種身份認證中有什么差別。

      在ASP.NET身份認證過程中,IPrincipal和IIdentity這二個接口有著非常重要的作用。 前者定義用戶對象的基本功能,后者定義標識對象的基本功能, 不同的身份認證方式得到的這二個接口的實例也是不同的。

      ASP.NET Windows身份認證是由WindowsAuthenticationModule實現的。 WindowsAuthenticationModule在ASP.NET管線的AuthenticateRequest事件中, 使用從IIS傳遞到ASP.NET的Windows訪問令牌(Token)創建一個WindowsIdentity對象,Token通過調用context.WorkerRequest.GetUserToken()獲得, 然后再根據WindowsIdentity 對象創建WindowsPrincipal對象, 然后把它賦值給HttpContext.User。

      在Forms身份認證中,我們需要創建登錄頁面,讓用戶提交用戶名和密碼,然后檢查用戶名和密碼的正確性, 接下來創建一個包含FormsAuthenticationTicket對象的登錄Cookie供后續請求使用。 FormsAuthenticationModule在ASP.NET管線的AuthenticateRequest事件中, 解析登錄Cookie并創建一個包含FormsIdentity的GenericPrincipal對象, 然后把它賦值給HttpContext.User。

      上面二段話簡單了概括了二種身份認證方式的工作方式。
      我們可以發現它們存在以下差別:
      1. Forms身份認證需要Cookie表示登錄狀態,Windows身份認證則依賴于IIS
      2. Windows身份認證不需要我們設計登錄頁面,不用編寫登錄驗證邏輯,因此更容易使用。

      在授權階段,UrlAuthorizationModule仍然會根據當前用戶檢查將要訪問的資源是否得到許可。 接下來,FileAuthorizationModule檢查 HttpContext.User.Identity 屬性中的 IIdentity 對象是否是 WindowsIdentity 類的一個實例。 如果 IIdentity 對象不是 WindowsIdentity 類的一個實例,則 FileAuthorizationModule 類停止處理。 如果存在 WindowsIdentity 類的一個實例,則 FileAuthorizationModule 類調用 AccessCheck Win32 函數(通過 P/Invoke) 來確定是否授權經過身份驗證的客戶端訪問請求的文件。 如果該文件的安全描述符的隨機訪問控制列表 (DACL) 中至少包含一個 Read 訪問控制項 (ACE),則允許該請求繼續。 否則,FileAuthorizationModule 類調用 HttpApplication.CompleteRequest 方法并將狀態碼 401 返回到客戶端。

      在Windows身份認證中,驗證工作主要是由IIS實現的,WindowsAuthenticationModule其實只是負責創建WindowsPrincipal和WindowsIdentity而已。 順便介紹一下:Windows 身份驗證又分為“NTLM 身份驗證”和“Kerberos v5 身份驗證”二種, 關于這二種Windows身份認證的更多說明可查看MSDN技術文章:解釋:ASP.NET 2.0 中的 Windows 身份驗證。 在我看來,IIS最終使用哪種Windows身份認證方式并不影響我們的開發過程,因此本文不會討論這個話題。

      根據我的實際經驗來看,使用Windows身份認證時,主要的開發工作將是根據登錄名從Active Directory獲取用戶信息。 因為,此時不需要我們再設計登錄過程,IIS與ASP.NET已經為我們準備好了WindowsPrincipal和WindowsIdentity這二個與用戶身份相關的對象。

      訪問 Active Directory

      我們通常使用LDAP協議來訪問Active Directory, 在.net framework中提供了DirectoryEntry和DirectorySearcher這二個類型讓我們可以方便地從托管代碼中訪問 Active Directory 域服務。

      如果我們要在"test.corp”這個域中搜索某個用戶信息,我們可以使用下面的語句構造一個DirectoryEntry對象:

      
      DirectoryEntry entry = new DirectoryEntry("LDAP://test.corp");
      
      

      在這段代碼中,我采用硬編碼的方式把域名寫進了代碼。
      我們如何知道當前電腦所使用的是哪個域名呢?
      答案是:查看“我的電腦”的屬性對話框:

      注意:這個域名不一定與System.Environment.UserDomainName相同。

      除了可以查看“我的電腦”的屬性對話框外,我們還可以使用代碼的方式獲取當前電腦所使用的域名:

      private static string GetDomainName()
      {
          // 注意:這段代碼需要在Windows XP及較新版本的操作系統中才能正常運行。
          SelectQuery query = new SelectQuery("Win32_ComputerSystem");
          using( ManagementObjectSearcher searcher = new ManagementObjectSearcher(query) ) {
              foreach( ManagementObject mo in searcher.Get() ) {
                  if( (bool)mo["partofdomain"] )
                      return mo["domain"].ToString();
              }
          }
          return null;
      }
      

      當構造了DirectorySearcher對象后,我們便可以使用DirectorySearcher來執行對Active Directory的搜索。
      我們可以使用下面的步驟來執行搜索:
      1. 設置 DirectorySearcher.Filter 指示LDAP格式篩選器,這是一個字符串。
      2. 多次調用PropertiesToLoad.Add() 設置搜索過程中要檢索的屬性列表。
      3. 調用FindOne() 方法獲取搜索結果。

      下面的代碼演示了如何從Active Directory中搜索登錄名為“fl45”的用戶信息:

      static void Main(string[] args)
      {
          Console.WriteLine(Environment.UserDomainName);
          Console.WriteLine(Environment.UserName);
          Console.WriteLine("------------------------------------------------");
      
          ShowUserInfo("fl45", GetDomainName());
      }
      
      private static string AllProperties = "name,givenName,samaccountname,mail";
      
      public static void ShowUserInfo(string loginName, string domainName)
      {
          if( string.IsNullOrEmpty(loginName) || string.IsNullOrEmpty(domainName) )
              return;
      
          string[] properties = AllProperties.Split(new char[] { '\r', '\n', ',' }, 
                              StringSplitOptions.RemoveEmptyEntries);
      
          try {
              DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName);
              DirectorySearcher search = new DirectorySearcher(entry);
              search.Filter = "(samaccountname=" + loginName + ")";
      
              foreach( string p in properties )
                  search.PropertiesToLoad.Add(p);
      
              SearchResult result = search.FindOne();
      
              if( result != null ) {
                  foreach( string p in properties ) {
                      ResultPropertyValueCollection collection = result.Properties[p];
                      for( int i = 0; i < collection.Count; i++ )
                          Console.WriteLine(p + ": " + collection[i]);
                  }
              }
          }
          catch( Exception ex ) {
              Console.WriteLine(ex.ToString());
          }
      }
      

      結果如下:

      在前面的代碼,我在搜索Active Directory時,只搜索了"name,givenName,samaccountname,mail"這4個屬性。 然而,LDAP還支持更多的屬性,我們可以使用下面的代碼查看更多的用戶信息:

      在ASP.NET中訪問Active Directory

      前面我在一個控制臺程序中演示了訪問Active Directory的方法,通過示例我們可以看到:在代碼中,我用Environment.UserName就可以得到當前用戶的登錄名。 然而,如果是在ASP.NET程序中,訪問Environment.UserName就很有可能得不到真正用戶登錄名。 因為:Environment.UserName是使用WIN32API中的GetUserName獲取線程相關的用戶名,但ASP.NET運行在IIS中,線程相關的用戶名就不一定是客戶端的用戶名了。 不過,ASP.NET可以模擬用戶方式運行,通過這種方式才可以得到正確的結果。關于“模擬”的話題在本文的后面部分有說明。

      在ASP.NET中,為了能可靠的獲取登錄用戶的登錄名,我們可以使用下面的代碼:

      /// <summary>
      /// 根據指定的HttpContext對象,獲取登錄名。
      /// </summary>
      /// <param name="context"></param>
      /// <returns></returns>
      public static string GetUserLoginName(HttpContext context)
      {
          if( context == null )
              return null;
      
          if( context.Request.IsAuthenticated == false )
              return null;
      
          string userName = context.User.Identity.Name;
          // 此時userName的格式為:UserDomainName\LoginName
          // 我們只需要后面的LoginName就可以了。
      
          string[] array = userName.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
          if( array.Length == 2 )
              return array[1];
      
          return null;
      }
      

      在ASP.NET中使用Windows身份認證時,IIS和WindowsAuthenticationModule已經做了許多驗證用戶的相關工作, 雖然我們可以使用前面的代碼獲取到用戶的登錄名,但用戶的其它信息即需要我們自己來獲取。 在實際使用Windows身份認證時,我們要做的事:基本上就是從Active Directory中根據用戶的登錄名獲取所需的各種信息。

      比如:我的程序在運行時,還需要使用以下與用戶相關的信息:

      public sealed class UserInfo
      {
          public string GivenName;
          public string FullName;
          public string Email;
      }
      
      

      那么,我們可以使用這樣的代碼來獲取所需的用戶信息:

      使用UserHelper的頁面代碼:

      <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
          <title>WindowsAuthentication DEMO  - http://www.rzrgm.cn/fish-li/</title>
      </head>
      <body>
      <% if( Request.IsAuthenticated ) { %>
          當前登錄全名:<%= Context.User.Identity.Name.HtmlEncode()%> <br />
          
          <% var user = UserHelper.GetCurrentUserInfo(Context); %>
          <% if( user != null ) { %>
              用戶短名:<%= user.GivenName.HtmlEncode()%> <br />
              用戶全名:<%= user.FullName.HtmlEncode() %> <br />
              郵箱地址:<%= user.Email.HtmlEncode() %>
          <% } %>    
      <% } else { %>
          當前用戶還未登錄。
      <% } %>
      </body>
      </html>
      
      

      程序運行的效果如下:

      另外,還可以從Active Directory查詢一個叫做memberof的屬性(它與Windows用戶組無關),有時候可以用它區分用戶,設計與權限相關的操作。

      在設計數據持久化的表結構時,由于此時沒有“用戶表”,那么我們可以直接保存用戶的登錄名。 剩下的開發工作就與Forms身份認證沒有太多的差別了。

      使用Active Directory驗證用戶身份

      前面介紹了ASP.NET Windows身份認證,在這種方式下,IIS和WindowsAuthenticationModule為我們實現了用戶身份認證的過程。 然而,有時可能由于各種原因,需要我們以編程的方式使用Active Directory驗證用戶身份,比如:在WinForm程序,或者其它的驗證邏輯。

      我們不僅可以從Active Directory中查詢用戶信息,也可以用它來實現驗證用戶身份,這樣便可以實現自己的登錄驗證邏輯。

      不管是如何使用Active Directory,我們都需要使用DirectoryEntry和DirectorySearcher這二個對象。 DirectoryEntry還提供一個構造函數可讓我們輸入用戶名和密碼:

      // 摘要:
      //     初始化 System.DirectoryServices.DirectoryEntry 類的新實例。
      //
      // 參數:
      //   Password:
      //     在對客戶端進行身份驗證時使用的密碼。DirectoryEntry.Password 屬性初始化為該值。
      //
      //   username:
      //     在對客戶端進行身份驗證時使用的用戶名。DirectoryEntry.Username 屬性初始化為該值。
      //
      //   Path:
      //     此 DirectoryEntry 的路徑。DirectoryEntry.Path 屬性初始化為該值。
      public DirectoryEntry(string path, string username, string password);
      
      

      要實現自己的登錄檢查,就需要使用這個構造函數。
      以下是我寫用WinForm寫的一個登錄檢查的示例:

      private void btnLogin_Click(object sender, EventArgs e)
      {
          if( txtUsername.Text.Length == 0 || txtPassword.Text.Length == 0 ) {
              MessageBox.Show("用戶名或者密碼不能為空。", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
              return;
          }
      
          string ldapPath = "LDAP://" + GetDomainName();
          string domainAndUsername = Environment.UserDomainName + "\\" + txtUsername.Text;
          DirectoryEntry entry = new DirectoryEntry(ldapPath, domainAndUsername, txtPassword.Text);
      
          DirectorySearcher search = new DirectorySearcher(entry);
      
          try {
              SearchResult result = search.FindOne();
      
              MessageBox.Show("登錄成功。", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
          }
          catch( Exception ex ) {
              // 如果用戶名或者密碼不正確,也會拋出異常。
              MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Stop);
          }
      }
      

      程序運行的效果如下:

      安全上下文與用戶模擬

      在ASP.NET Windows身份認證環境中,與用戶相關的安全上下文對象保存在HttpContext.User屬性中,是一個類型為WindowsPrincipal的對象, 我們還可以訪問HttpContext.User.Identity來獲取經過身份認證的用戶標識,它是一個WindowsIdentity類型的對象。

      在.NET Framework中,我們可以通過WindowsIdentity.GetCurrent()獲取與當前線程相關的WindowsIdentity對象, 這種方法獲取的是當前運行的Win32線程的安全上下文標識。 由于ASP.NET運行在IIS進程中,因此ASP.NET線程的安全標識其實是從IIS的進程中繼承的, 所以此時用二種方法得到的WindowsIdentity對象其實是不同的。

      在Windows操作系統中,許多權限檢查都是基于Win32線程的安全上下文標識, 于是前面所說的二種WindowsIdentity對象會造成編程模型的不一致問題, 為了解決這個問題,ASP.NET提供了“模擬”功能,允許線程以特定的Windows帳戶的安全上下文來訪問資源。

      為了能更好的理解模擬的功能,我準備了一個示例(ShowWindowsIdentity.ashx):

      public class ShowWindowsIdentity : IHttpHandler {
          
          public void ProcessRequest (HttpContext context) {
              // 要觀察【模擬】的影響,
              // 可以啟用,禁止web.config中的設置:<identity impersonate="true"/>
              
              context.Response.ContentType = "text/plain";
      
              context.Response.Write(Environment.UserDomainName + "\\" + Environment.UserName + "\r\n");
              
              WindowsPrincipal winPrincipal = (WindowsPrincipal)HttpContext.Current.User;
              context.Response.Write(string.Format("HttpContext.Current.User.Identity: {0}, {1}\r\n", 
                      winPrincipal.Identity.AuthenticationType, winPrincipal.Identity.Name));
              
              WindowsPrincipal winPrincipal2 = (WindowsPrincipal)Thread.CurrentPrincipal;
              context.Response.Write(string.Format("Thread.CurrentPrincipal.Identity: {0}, {1}\r\n",
                      winPrincipal2.Identity.AuthenticationType, winPrincipal2.Identity.Name));
      
              WindowsIdentity winId = WindowsIdentity.GetCurrent();
              context.Response.Write(string.Format("WindowsIdentity.GetCurrent(): {0}, {1}",
                      winId.AuthenticationType, winId.Name));
          }
      

      首先,在web.config中設置:

      
      <authentication mode="Windows" />
      
      

      注意:要把網站部署在IIS中,否則看不出效果。

      此時,訪問ShowWindowsIdentity.ashx,將看到如下圖所示的結果:

      現在修改一下web.config中設置:(注意:后面加了一句配置

      
      <authentication mode="Windows" />
      <identity impersonate="true"/>
      
      

      此時,訪問ShowWindowsIdentity.ashx,將看到如下圖所示的結果:

      說明:
      1. FISH-SRV2003是我的計算機名。它在一個沒有域的環境中。
      2. fish-li是我的一個Windows帳號的登錄名。
      3. 網站部署在IIS6中,進程以NETWORK SERVICE帳號運行。
      4. 打開網頁時,我輸入的用戶名是fish-li

      前面二張圖片的差異之處其實也就是ASP.NET的“模擬”所發揮的功能。

      關于模擬,我想說四點:
      1. 在ASP.NET中,我們應該訪問HttpContext.User.Identity獲取當前用戶標識,那么就不存在問題(此時可以不需要模擬),例如FileAuthorizationModule就是這樣處理的。
      2. 模擬只是在ASP.NET應用程序訪問Windows系統資源時需要應用Windows的安全檢查功能才會有用。
      3. Forms身份認證也能配置模擬功能,但只能模擬一個Windows帳戶。
      4. 絕大多數情況下是不需要模擬的。

      在IIS中配置Windows身份認證

      與使用Forms身份認證的程序不同,使用Windows身份認證的程序需要額外的配置步驟。 這個小節將主要介紹在IIS中配置Windows身份認證,我將常用的IIS6和IIS7.5為例分別介紹這些配置。

      IIS6的配置 請參考下圖:

      IIS7.5的配置 請參考下圖:

      注意:Windows身份認證是需要安裝的,方法請參考下圖:

      關于瀏覽器的登錄對話框問題

      當我們用瀏覽器訪問一個使用Windows身份認證的網站時,瀏覽器都會彈出一個對話框(左IE,右Safari):

      此時,要求我們輸入Windows的登錄帳號,然后交給IIS驗證身份。

      首次彈出這個對話框很正常:因為程序要驗證用戶的身份。
      然而,每次關閉瀏覽器下次重新打開頁面時,又會出現此對話框,此時感覺就很不方便了。
      雖然有些瀏覽器能記住用戶名和密碼,但我發現FireFox,Opera,Chrome仍然會彈出這個對話框,等待我們點擊確定, 只有Safari才不會打擾用戶直接打開網頁。 IE的那個“記住我的密碼”復選框完全是個擺設,它根本不會記住密碼!

      因此,我所試過的所有瀏覽器中,只有Safari是最人性化的。
      雖然在默認情況下,雖然IE不會記住密碼,每次都需要再次輸入。
      不過,IE卻可以支持不提示用戶輸入登錄帳號而直接打開網頁, 此時IE將使用用戶的當前Windows登錄帳號傳遞給IIS驗證身份。

      要讓IE打開一個Windows身份認證的網站不提示登錄對話框,必須滿足以下條件:
      1. 必須在 IIS 的 Web 站點屬性中啟用 Windows 集成身份驗證。
      2. 客戶端和Web服務器都必須在基于Microsoft Windows的同一個域內。
      3. Internet Explorer 必須把所請求的 URL 視為 Intranet(本地)。
      4. Internet Explorer 的 Intranet 區域的安全性設置必須設為“只在 Intranet 區域自動登錄”。
      5. 請求Web頁的用戶必須具有訪問該Web頁以及該Web頁中引用的所有對象的適當的文件系統(NTFS)權限。
      6. 用戶必須用域帳號登錄到Windows 。

      在這幾個條件中,如果網站是在一個Windows域中運行,除了第3條可能不滿足外,其它條件應該都容易滿足(第4條是默認值)。 因此,要讓IE不提示輸入登錄帳號,只要確保第3條滿足就可以了。 下面的圖片演示了如何完成這個配置:(注意:配置方法也適合用域名訪問的情況)

      另外,除了在IE中設置Intranet外,還可以在訪問網站時,用計算機名代替IP地址或者域名, 那么IE始終認為是在訪問Intranet內的網站,此時也不會彈出登錄對話框。

      在此,我想再啰嗦三句:
      1. IE在集成Windows身份認證時,雖然不提示登錄對話框,但是不表示不安全,它會自動傳遞登錄憑據。
      2. 這種行為只有IE才能支持。(其它的瀏覽器只是會記住密碼,在實現上其實是不一樣的。)
      3. 集成Windows身份認證,也只適合在Intranet的環境中使用。

      在客戶端代碼中訪問Windows身份認證的頁面

      在上篇博客中,我演示了如何用代碼訪問一個使用Forms身份認證的網站中的受限頁面,方法是使用CookieContainer對象接收服務端生的登錄Cookie。 然而,在Windows身份認證的網站中,身份驗證的過程發生在IIS中,而且根本不使用Cookie保存登錄狀態,而是需要在請求時發送必要的身份驗證信息。

      在使用代碼做為客戶端訪問Web服務器時,我們仍然需要使用HttpWebRequest對象。 為了能讓HttpWebRequest在訪問IIS時發送必要的身份驗證信息,HttpWebRequest提供二個屬性都可以完成這個功能:

      // 獲取或設置請求的身份驗證信息。
      //
      // 返回結果:
      //     包含與該請求關聯的身份驗證憑據的 System.Net.ICredentials。默認為 null。
      public override ICredentials Credentials { get; set; }
      
      
      // 獲取或設置一個 System.Boolean 值,該值控制默認憑據是否隨請求一起發送。
      //
      // 返回結果:
      //     如果使用默認憑據,則為 true;否則為 false。默認值為 false。
      public override bool UseDefaultCredentials { get; set; }
      

      下面是我準備的完整的示例代碼(注意代碼中的注釋)

      static void Main(string[] args)
      {
          try {
              // 請把WindowsAuthWebSite1這個網站部署在IIS中,
              // 開啟Windows認證方式,并禁止匿名用戶訪問。
              // 然后修改下面的訪問地址。
              HttpWebRequest request = 
                  (HttpWebRequest)WebRequest.Create("http://localhost:33445/Default.aspx");
      
              // 下面三行代碼,啟用任意一行都是可以的。
              request.UseDefaultCredentials = true;
              //request.Credentials = CredentialCache.DefaultCredentials;
              //request.Credentials = CredentialCache.DefaultNetworkCredentials;
              // 如果上面的三行代碼全被注釋了,那么將會看到401的異常信息。
      
              using( HttpWebResponse response = (HttpWebResponse)request.GetResponse() ) {
                  using( StreamReader sr = new StreamReader(response.GetResponseStream()) ) {
                      Console.WriteLine(sr.ReadToEnd());
                  }
              }
          }
          catch( WebException wex ) {
              Console.WriteLine("=====================================");
              Console.WriteLine("異常發生了。");
              Console.WriteLine("=====================================");
              Console.WriteLine(wex.Message);
          }
      }
      

      其實關鍵部分還是設置UseDefaultCredentials或者Credentials,代碼中的三種方法是有效的。
      這三種方法的差別:
      1. Credentials = CredentialCache.DefaultCredentials; 表示在發送請求會帶上當前用戶的身份驗證憑據。
      2. UseDefaultCredentials = true; 此方法在內部會調用前面的方法,因此與前面的方法是一樣的。
      3. Credentials = CredentialCache.DefaultNetworkCredentials; 是在.NET 2.0中引用的新方法。

      關于DefaultCredentials和DefaultNetworkCredentials的更多差別,請看我整理的表格:

      Credentials屬性申明類型實例類型.NET支持版本
      DefaultCredentialsICredentialsSystemNetworkCredential從1.0開始
      DefaultNetworkCredentialsNetworkCredentialSystemNetworkCredential從2.0開始

      三個類型的繼承關系:
      1. NetworkCredential實現了ICredentials接口,
      2. SystemNetworkCredential繼承自NetworkCredential。

      在結束這篇博客之前,我想我應該感謝新蛋。
      在新蛋的網絡環境中,讓我學會了使用Windows身份認證。
      除了感謝之外,我現在還特別懷念 fl45 這個登錄名......

      點擊此處下載示例代碼

      posted on 2012-05-07 08:27  Fish Li  閱讀(80855)  評論(106)    收藏  舉報
      主站蜘蛛池模板: 免费无码AV一区二区波多野结衣| 精品蜜臀国产av一区二区| 亚洲毛片不卡AV在线播放一区| 安溪县| 国産精品久久久久久久| 国产中年熟女大集合| 无码天堂va亚洲va在线va| 久久99精品久久久久麻豆| 疯狂做受XXXX高潮国产| 无码av天天av天天爽| 亚洲AV熟妇在线观看| 亚洲成人精品综合在线| 亚洲熟妇无码av另类vr影视| 国产精品天堂蜜av在线播放| 成人免费无码av| 国产中文字幕在线精品| 日韩有码中文在线观看| 济宁市| 久久午夜无码鲁丝片直播午夜精品 | 18禁网站免费无遮挡无码中文| 松江区| 国产毛片精品一区二区色| 国产精品蜜臀av在线一区| 国产大学生自拍三级视频| 亚洲av色香蕉一二三区| 丰满人妻熟妇乱又仑精品| 國產尤物AV尤物在線觀看| 国产成人综合色在线观看网站| 激情综合网激情五月我去也| 国内精品免费久久久久电影院97| 男女爽爽无遮挡午夜视频| 亚洲AV永久中文无码精品综合| 精品人妻午夜一区二区三区四区| 国产91特黄特色A级毛片| 久久国产精品精品国产色婷婷| 成人精品大片—懂色av| 国产精品视频一区二区不卡| 久久精品人妻无码一区二区三区| 国产高清免费午夜在线视频| 五月天丁香婷婷亚洲欧洲国产| 国产高清国产精品国产专区|