亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

利用自定義的AuthenticationFilter實(shí)現(xiàn)Basic認(rèn)證

系統(tǒng) 1843 0

[ASP.NET MVC] 利用自定義的AuthenticationFilter實(shí)現(xiàn)Basic認(rèn)證

?

很多情況下目標(biāo)Action方法都要求在一個(gè)安全上下文中被執(zhí)行,這里所謂的安全上下文主要指的是當(dāng)前請(qǐng)求者是一個(gè)經(jīng)過授權(quán)的用戶。授權(quán)的本質(zhì)就是讓用戶在他許可的權(quán)限范圍內(nèi)做他能夠做的事情,授權(quán)的前提是請(qǐng)求者是一個(gè)經(jīng)過認(rèn)證的用戶。質(zhì)詢-應(yīng)答(Chanllenge-Response)”是用戶認(rèn)證采用的一種常用的形式,認(rèn)證方向被認(rèn)證方發(fā)出質(zhì)詢以要求其提供用于實(shí)施認(rèn)證的用戶憑證,而被認(rèn)證方提供相應(yīng)的憑證以作為對(duì)質(zhì)詢的應(yīng)答。旨在目標(biāo)Action方法執(zhí)行之前實(shí)施身分認(rèn)證的AuthenticationFilter也對(duì)這種認(rèn)證方法提供了支持。

一、IAuthenticationFilter接口

所有的AuthenticationFilter類型均實(shí)現(xiàn)了IAuthenticationFilter接口,該接口定義在命名空間“System.Web.Mvc.Filters”下(其他四種過濾器接口都定義在“System.Web.Mvc”命名空間下)。如下面的代碼片斷所示,OnAuthentication和OnAuthenticationChallenge這兩個(gè)方法被定義在此接口中,前者用于對(duì)請(qǐng)求實(shí)施認(rèn)證,后者則負(fù)責(zé)將相應(yīng)的認(rèn)證質(zhì)詢發(fā)送給請(qǐng)求者。

                
                     1:
                
                
                  public
                
                
                  interface
                
                 IAuthenticationFilter
              
                
                     2:
                
                 {
              
                
                     3:
                
                
                  void
                
                 OnAuthentication(AuthenticationContext filterContext);
              
                
                     4:
                
                
                  void
                
                 OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
              
                
                     5:
                
                 }
              

定義在IAuthenticationFilter接口的兩個(gè)方法都將一個(gè)上下文對(duì)象作為其唯一參數(shù)。OnAuthentication方法的這個(gè)參數(shù)類型為AuthenticationContext,如下面的代碼片斷所示,它是ControllerContext的子類。AuthenticationContext的ActionDescriptor返回的自然是用于描述目標(biāo)Action方法的ActionDescriptor對(duì)象。借助于Principal屬性,我們可以獲取或設(shè)置代表當(dāng)前用戶的Principal對(duì)象。如果我們?cè)趫?zhí)行OnAuthentication方法的過程中設(shè)置了AuthenticationContext的Result屬性,提供的ActionResult將直接用于響應(yīng)當(dāng)前請(qǐng)求。

                
                     1:
                
                
                  public
                
                
                  class
                
                 ActionExecutingContext : ControllerContext
              
                
                     2:
                
                 {    
              
                
                     3:
                
                
                  public
                
                 ActionExecutingContext();
              
                
                     4:
                
                
                  public
                
                 ActionExecutingContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor,IDictionary<
                
                  string
                
                , 
                
                  object
                
                > actionParameters);
              
                
                     5:
                
                ? 
              
                
                     6:
                
                
                  public
                
                
                  virtual
                
                 ActionDescriptor             ActionDescriptor { get; set; }
              
                
                     7:
                
                
                  public
                
                
                  virtual
                
                 IDictionary<
                
                  string
                
                , 
                
                  object
                
                >  ActionParameters { get; set; }
              
                
                     8:
                
                
                  public
                
                 ActionResult                         Result { get; set; }
              
                
                     9:
                
                 }
              

OnAuthenticationChallenge方法的參數(shù)類型為AuthenticationChallengeContext。如下面的代碼片斷所示,它依然是ControllerContext的子類。它同樣具有一個(gè)用于描述目標(biāo)Action方法的ActionDescriptor屬性,其Result屬性代表的ActionResult對(duì)象將用于響應(yīng)當(dāng)前請(qǐng)求。

                
                     1:
                
                
                  public
                
                
                  class
                
                 ActionExecutedContext : ControllerContext
              
                
                     2:
                
                 {    
              
                
                     3:
                
                
                  public
                
                 ActionExecutedContext();   
              
                
                     4:
                
                
                  public
                
                 ActionExecutedContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor, 
                
                  bool
                
                 canceled, Exception exception);
              
                
                     5:
                
                ? 
              
                
                     6:
                
                
                  public
                
                
                  virtual
                
                 ActionDescriptor     ActionDescriptor { get; set; }
              
                
                     7:
                
                
                  public
                
                
                  virtual
                
                
                  bool
                
                                 Canceled { get; set; }
              
                
                     8:
                
                
                  public
                
                
                  virtual
                
                 Exception            Exception { get; set; }
              
                
                     9:
                
                
                  public
                
                
                  bool
                
                                         ExceptionHandled { get; set; }
              
                
                    10:
                
                
                  public
                
                 ActionResult                 Result { get; set; }
              
                
                    11:
                
                 }
              

二、AuthenticationFilter的執(zhí)行流程

我們知道身份認(rèn)證總是對(duì)請(qǐng)求處理的第一個(gè)步驟,因?yàn)橹挥写_定了請(qǐng)求者的真實(shí)身份,安全才能得到保障,所以AuthenticationFilter是最先被執(zhí)行的一類過濾器。所有過濾器的執(zhí)行都是ActionInvoker來驅(qū)動(dòng)的,ASP.NET MVC在默認(rèn)情況下采用的ActionInvoker是一個(gè)AsyncControllerActionInvoker對(duì)象,后者類型派生于ControllerActionInvoker。ControllerActionInvoker針對(duì)AuthenticationFilter的執(zhí)行體現(xiàn)在如下兩個(gè)方法(InvokeAuthenticationFilters和InvokeAuthenticationFiltersChallenge)上。

                
                     1:
                
                
                  public
                
                
                  class
                
                 ControllerActionInvoker : IActionInvoker
              
                
                     2:
                
                 {
              
                
                     3:
                
                
                  //其他成員
                
              
                
                     4:
                
                
                  protected
                
                
                  virtual
                
                 AuthenticationContext InvokeAuthenticationFilters(ControllerContext controllerContext,IList<IAuthenticationFilter> filters, ActionDescriptor actionDescriptor);
              
                
                     5:
                
                
                  protected
                
                
                  virtual
                
                 AuthenticationChallengeContext InvokeAuthenticationFiltersChallenge(ControllerContext controllerContext, IList<IAuthenticationFilter> filters, ActionDescriptor actionDescriptor, ActionResult result);   
              
                
                     6:
                
                 }
              
如果多個(gè)AuthenticationFilter同時(shí)被應(yīng)用到目標(biāo)Action方法上,ControllerActionInvoker會(huì)根據(jù)對(duì)應(yīng)Filter的Order/Scope屬性對(duì)它們進(jìn)行排序。隨后ControllerActionInvoker會(huì)根據(jù)當(dāng)前ControllerContext、描述目標(biāo)Action方法的ActionDescriptor對(duì)象以及原始的Principal(對(duì)應(yīng)于當(dāng)前HttpContext的User屬性)創(chuàng)建一個(gè)AuthenticationContext對(duì)象,并以此作為參數(shù)以此調(diào)用每個(gè)AuthenticationFilter對(duì)象的OnAuthentication對(duì)象實(shí)施認(rèn)證。

在目標(biāo)Action方法被執(zhí)行之后,通過本書第11章“View的呈現(xiàn)”我們知道最終執(zhí)行的結(jié)果會(huì)被封裝為一個(gè)ActionResult對(duì)象。ControllerActionInvoker會(huì)利用當(dāng)前ControllerContext、描述目標(biāo)Action方法的ActionDescriptor對(duì)象和這個(gè)ActionResult創(chuàng)建一個(gè)AuthenticationChallengeContext對(duì)象,并將其作為參數(shù)依次調(diào)用每個(gè)AuthenticationFilter的OnAuthenticationChallenge方法。這個(gè)AuthenticationChallengeContext對(duì)象的Result屬性最終返回的ActionResult對(duì)象將被用來對(duì)請(qǐng)求予以響應(yīng)。

右圖基本反映了整個(gè)“AuthenticationFilter鏈”的執(zhí)行流程, 但是如果在執(zhí)行某個(gè)AuthenticationFilter對(duì)象的OnAuthenticatio方法時(shí)對(duì)作為參數(shù)的AuthenticationContext對(duì)象的Result屬性作了相應(yīng)的設(shè)置,針對(duì)整個(gè)“AuthenticationFilter鏈”的執(zhí)行將會(huì)立即中止,指定的這個(gè)ActionResult對(duì)象將用于響應(yīng)當(dāng)前請(qǐng)求 。如果在執(zhí)行過程中對(duì)AuthenticationContext對(duì)象的Principal屬性作了相應(yīng)的設(shè)置,該屬性值將會(huì)作為當(dāng)前HttpContext和當(dāng)前線程的Principal。

三、實(shí)例演示:通過自定義AuthenticationFilter實(shí)現(xiàn)Basic認(rèn)證

在ASP.NET MVC的應(yīng)用編程接口中,我們找不到IAuthenticationFilter接口的實(shí)現(xiàn)者。為了讓大家對(duì)這個(gè)在ASP.NET MVC 5才引入的過濾器具有更加深刻的認(rèn)識(shí),我們接下來會(huì)通過一個(gè)實(shí)例來演示如何通過自定義的AuthenticationFilter實(shí)現(xiàn)針對(duì)Basic方案的認(rèn)證。不過在這之前,我們有必要對(duì)Basic這種基本的認(rèn)證方法作一個(gè)基本的了解。Basic和Digest是兩種典型的HTTP認(rèn)證方案。對(duì)于前者,雖然客戶端提供的認(rèn)證憑證(用戶名+密碼)僅僅是被Base64編碼而沒有被加密,但是我們可以通過采用HTTPS傳輸利用SSL來解決機(jī)密性的問題,所以Basic認(rèn)證也不失為一種不錯(cuò)的認(rèn)證方案。左圖體現(xiàn)了Basic認(rèn)證的基本流程,可以看出這也是一種典型的采用“質(zhì)詢-應(yīng)答”模式的認(rèn)證方案,整個(gè)流程包含如下兩個(gè)基本步驟。

  • 客戶端向服務(wù)端發(fā)送一個(gè)HTTP請(qǐng)求,服務(wù)端返回一個(gè)狀態(tài)為“401, Unauthorized”的響應(yīng)。該響應(yīng)具有一個(gè)“WWW-Authenticate”的報(bào)頭標(biāo)明采用的是Basic認(rèn)證方案。Basic認(rèn)證是在一個(gè)“領(lǐng)域(Realm)”限定的上下文中進(jìn)行的,該報(bào)頭還可以執(zhí)行認(rèn)證的領(lǐng)域,左圖所示的WWW-Authenticate報(bào)頭值為:Basic realm="localhost"。
  • · 客戶端向服務(wù)端發(fā)送一個(gè)攜帶基于用戶名/密碼的認(rèn)證憑證的請(qǐng)求。認(rèn)證憑證的格式為“{UserName}:{Password}”,并采用Base64編碼(編碼的目的不是為了保護(hù)提供的密碼)。這樣一個(gè)經(jīng)過編碼的認(rèn)證憑證被存放在請(qǐng)求報(bào)頭Authorization中,相應(yīng)的認(rèn)證方案類型(Basic)依然需要在該報(bào)頭中指定,左圖所示的Authorization報(bào)頭值為:Basic YcdfaYsss==。服務(wù)端接收到請(qǐng)求之后,從Authorization報(bào)頭中提取憑證并對(duì)其進(jìn)行解碼,最后采用提取的用戶名和密碼實(shí)施認(rèn)證。認(rèn)證成功之后,該請(qǐng)求會(huì)得到正常的處理,并回復(fù)一個(gè)正常的響應(yīng)。

在正式介紹如果定義這個(gè)實(shí)現(xiàn)Basic認(rèn)證的AuthenticationFilter之前,我們不妨先來看看使用了這個(gè)自定義AuthenticationFilter會(huì)產(chǎn)生怎樣的效果。我們?cè)谝粋€(gè)ASP.NET MVC應(yīng)用中定義了如下一個(gè)HomeController,定義其中的默認(rèn)Action方法Index會(huì)輸出以三種形式體現(xiàn)的“當(dāng)前用戶名”。HomeController類型上應(yīng)用的AuthenticateAttribute特性正是我們自定義的AuthenticationFilter。

                
                     1:
                
                
                   [Authenticate]
                
              
                
                     2:
                
                
                  public
                
                
                  class
                
                 HomeController : Controller
              
                
                     3:
                
                 {
              
                
                     4:
                
                
                  public
                
                
                  void
                
                 Index()
              
                
                     5:
                
                     {
              
                
                     6:
                
                         Response.Write(
                
                  string
                
                .Format(
                
                  "Controller.User: {0}<br/>"
                
                , 
                
                  this
                
                .User.Identity.Name));
              
                
                     7:
                
                         Response.Write(
                
                  string
                
                .Format(
                
                  "HttpContext.User: {0}<br/>"
                
                , 
                
                  this
                
                .ControllerContext.HttpContext.User.Identity.Name));
              
                
                     8:
                
                         Response.Write(
                
                  string
                
                .Format(
                
                  "Thread.CurrentPrincipal: {0}"
                
                , Thread.CurrentPrincipal.Identity.Name));
              
                
                     9:
                
                     }
              
                
                    10:
                
                 }
              

由于瀏覽器默認(rèn)提供對(duì)Basic認(rèn)證的支持,所以當(dāng)我們運(yùn)行該程序后如下圖所示的登錄對(duì)話框會(huì)自動(dòng)彈出,當(dāng)我們輸入正確的用戶名和密碼(用戶名和密碼直接維護(hù)在AuthenticateAttribute上)后,當(dāng)前登錄用戶名會(huì)呈現(xiàn)在瀏覽器上。

這個(gè)用于實(shí)現(xiàn)Basic認(rèn)證的AuthenticateAttribute定義如下,簡(jiǎn)單起見我們將帳號(hào)采用的用戶名和密碼保存在一個(gè)靜態(tài)字段中。具體的認(rèn)證實(shí)現(xiàn)在實(shí)現(xiàn)的OnAuthentication方法中,我們?cè)谠摲椒ㄖ姓{(diào)用IsAuthenticated判斷請(qǐng)是否經(jīng)過認(rèn)證,并在認(rèn)證成功的情況下得到代表請(qǐng)求用戶的Principal對(duì)象,然對(duì)作為參數(shù)的AuthenticationContext對(duì)象的Principal屬性進(jìn)行賦值。對(duì)于沒有經(jīng)過認(rèn)證的請(qǐng)求,我們會(huì)調(diào)用另一個(gè)方法ProcessUnauthenticatedRequest對(duì)其進(jìn)行處理。

                
                     1:
                
                
                  public
                
                
                  class
                
                 AuthenticateAttribute:FilterAttribute,IAuthenticationFilter
              
                
                     2:
                
                 {
              
                
                     3:
                
                
                  public
                
                
                  const
                
                
                  string
                
                 AuthorizationHeaderName           =
                
                  "Authorization"
                
                ;
              
                
                     4:
                
                
                  public
                
                
                  const
                
                
                  string
                
                 WwwAuthenticationHeaderName       =
                
                  "WWW-Authenticate"
                
                ;
              
                
                     5:
                
                
                  public
                
                
                  const
                
                
                  string
                
                 BasicAuthenticationScheme         =
                
                  "Basic"
                
                ;
              
                
                     6:
                
                
                  private
                
                
                  static
                
                 Dictionary<
                
                  string
                
                , 
                
                  string
                
                > userAccounters;
              
                
                     7:
                
                ? 
              
                
                     8:
                
                
                  static
                
                 AuthenticateAttribute()
              
                
                     9:
                
                     {
              
                
                    10:
                
                         userAccounters = 
                
                  new
                
                 Dictionary<
                
                  string
                
                , 
                
                  string
                
                >(StringComparer.OrdinalIgnoreCase);
              
                
                    11:
                
                ? 
              
                
                    12:
                
                         userAccounters.Add(
                
                  "Foo"
                
                , 
                
                  "Password"
                
                );
              
                
                    13:
                
                         userAccounters.Add(
                
                  "Bar"
                
                , 
                
                  "Password"
                
                );
              
                
                    14:
                
                         userAccounters.Add(
                
                  "Baz"
                
                , 
                
                  "Password"
                
                );
              
                
                    15:
                
                     }
              
                
                    16:
                
                ? 
              
                
                    17:
                
                
                  public
                
                
                  void
                
                 OnAuthentication(AuthenticationContext filterContext)
              
                
                    18:
                
                     {
              
                
                    19:
                
                         IPrincipal user;
              
                
                    20:
                
                
                  if
                
                 (
                
                  this
                
                .IsAuthenticated(filterContext, 
                
                  out
                
                 user))
              
                
                    21:
                
                         {
              
                
                    22:
                
                             filterContext.Principal = user;
              
                
                    23:
                
                         }
              
                
                    24:
                
                
                  else
                
              
                
                    25:
                
                         {
              
                
                    26:
                
                
                  this
                
                .ProcessUnauthenticatedRequest(filterContext);
              
                
                    27:
                
                         }
              
                
                    28:
                
                     }
              
                
                    29:
                
                ? 
              
                
                    30:
                
                
                  protected
                
                
                  virtual
                
                 AuthenticationHeaderValue GetAuthenticationHeaderValue(AuthenticationContext filterContext)
              
                
                    31:
                
                     {
              
                
                    32:
                
                
                  string
                
                 rawValue = filterContext.RequestContext.HttpContext.Request.Headers[AuthorizationHeaderName];
              
                
                    33:
                
                
                  if
                
                 (
                
                  string
                
                .IsNullOrEmpty(rawValue))
              
                
                    34:
                
                         {
              
                
                    35:
                
                
                  return
                
                
                  null
                
                ;
              
                
                    36:
                
                         }
              
                
                    37:
                
                
                  string
                
                [] split = rawValue.Split(
                
                  ' '
                
                );
              
                
                    38:
                
                
                  if
                
                 (split.Length != 2)
              
                
                    39:
                
                         {
              
                
                    40:
                
                
                  return
                
                
                  null
                
                ;
              
                
                    41:
                
                         }
              
                
                    42:
                
                
                  return
                
                
                  new
                
                 AuthenticationHeaderValue(split[0], split[1]);
              
                
                    43:
                
                     }
              
                
                    44:
                
                ? 
              
                
                    45:
                
                
                  protected
                
                
                  virtual
                
                
                  bool
                
                 IsAuthenticated(AuthenticationContext filterContext, 
                
                  out
                
                 IPrincipal user)
              
                
                    46:
                
                     {
              
                
                    47:
                
                         user = filterContext.Principal;
              
                
                    48:
                
                
                  if
                
                 (
                
                  null
                
                 != user & user.Identity.IsAuthenticated)
              
                
                    49:
                
                         {
              
                
                    50:
                
                
                  return
                
                
                  true
                
                ;
              
                
                    51:
                
                         }
              
                
                    52:
                
                ? 
              
                
                    53:
                
                         AuthenticationHeaderValue token = 
                
                  this
                
                .GetAuthenticationHeaderValue(filterContext);
              
                
                    54:
                
                
                  if
                
                 (
                
                  null
                
                 != token && token.Scheme ==  BasicAuthenticationScheme)
              
                
                    55:
                
                         {
              
                
                    56:
                
                
                  string
                
                 credential = Encoding.Default.GetString(Convert.FromBase64String(token.Parameter));
              
                
                    57:
                
                
                  string
                
                [] split = credential.Split(
                
                  ':'
                
                );
              
                
                    58:
                
                
                  if
                
                 (split.Length == 2)
              
                
                    59:
                
                             {
              
                
                    60:
                
                
                  string
                
                 userName = split[0];
              
                
                    61:
                
                
                  string
                
                 password;
              
                
                    62:
                
                
                  if
                
                 (userAccounters.TryGetValue(userName, 
                
                  out
                
                 password))
              
                
                    63:
                
                                 {
              
                
                    64:
                
                
                  if
                
                 (password == split[1])
              
                
                    65:
                
                                     {
              
                
                    66:
                
                                         GenericIdentity identity = 
                
                  new
                
                 GenericIdentity(userName);
              
                
                    67:
                
                                         user = 
                
                  new
                
                 GenericPrincipal(identity, 
                
                  new
                
                
                  string
                
                [0]);
              
                
                    68:
                
                
                  return
                
                
                  true
                
                ;
              
                
                    69:
                
                                     }
              
                
                    70:
                
                                 }
              
                
                    71:
                
                             }
              
                
                    72:
                
                         }
              
                
                    73:
                
                
                  return
                
                
                  false
                
                ;
              
                
                    74:
                
                     }
              
                
                    75:
                
                ? 
              
                
                    76:
                
                
                  protected
                
                
                  virtual
                
                
                  void
                
                 ProcessUnauthenticatedRequest(AuthenticationContext filterContext)
              
                
                    77:
                
                     {
              
                
                    78:
                
                
                  string
                
                 parameter = 
                
                  string
                
                .Format(
                
                  "realm=\"{0}\""
                
                , filterContext.RequestContext.HttpContext.Request.Url.DnsSafeHost);
              
                
                    79:
                
                         AuthenticationHeaderValue challenge = 
                
                  new
                
                 AuthenticationHeaderValue(BasicAuthenticationScheme, parameter);
              
                
                    80:
                
                         filterContext.HttpContext.Response.Headers[WwwAuthenticationHeaderName] = challenge.ToString();
              
                
                    81:
                
                         filterContext.Result = 
                
                  new
                
                 HttpUnauthorizedResult();
              
                
                    82:
                
                     }
              
                
                    83:
                
                ? 
              
                
                    84:
                
                
                  public
                
                
                  void
                
                 OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) {}
              
                
                    85:
                
                 }
              

在對(duì)請(qǐng)求實(shí)施認(rèn)證的IsAuthenticated方法中,我們會(huì)試圖從請(qǐng)求的Authorization報(bào)頭中提取安全憑證,并按照Basic憑證的格式解析出用戶名和密碼。只有在用戶名和密碼匹配的情況下,我們認(rèn)為請(qǐng)求通過認(rèn)證,并根據(jù)解析出來的用戶名創(chuàng)建一個(gè)GenericPrincipal對(duì)象作為輸出參數(shù)user的值。如果請(qǐng)求并為通過認(rèn)證(它可以是一個(gè)匿名請(qǐng)求,或者提供的用戶名與密碼不匹配),方法ProcessUnauthenticatedRequest會(huì)被調(diào)用。在此情況下,它會(huì)對(duì)響應(yīng)的WWW-Authenticate報(bào)頭進(jìn)行相應(yīng)的設(shè)置,并創(chuàng)建一個(gè)HttpUnauthorizedResult對(duì)象作為AuthenticationContext對(duì)象的Result屬性,那么客戶端最終會(huì)接收到一個(gè)狀態(tài)為“401, Unauthorized”的響應(yīng)。

作者: Artech
出處: http://artech.cnblogs.com/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
?
綠色通道:? 好文要頂? 已關(guān)注? 收藏該文 與我聯(lián)系 ?
11
0
?
(請(qǐng)您對(duì)文章做出評(píng)價(jià))
?
?? 上一篇: IoC在ASP.NET Web API中的應(yīng)用
posted @? 2014-04-16 09:21 ? Artech ?閱讀( 964 ) 評(píng)論( 15 )? 編輯 ? 收藏

?

?

利用自定義的AuthenticationFilter實(shí)現(xiàn)Basic認(rèn)證


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 欧美日韩久久 | 欧美激情精品久久久久久大尺度 | 亚洲免费色视频 | 天天操免费视频 | 宅男噜噜噜66一区二区 | 久久手机视频 | 国产成人mv在线观看入口视频 | www.亚洲成人.com | 久久综合九色综合97伊人麻豆 | 成人亚欧网站在线观看 | 黄色网址在线免费 | 久久精品国产99国产精品 | 欧美久久视频 | 中文字幕久久网 | 久久综合久久伊人 | 日本中文字幕一区二区 | 色综合综合在线 | 奇米视频在线观看 | 男女生性毛片免费观看 | 99久热re在线精品视频 | 精品国产品香蕉在线观看 | 在线精品国产第一页 | 天天干夜夜操视频 | 精品91精品91精品国产片 | 精品乱久久 | 国产香蕉75在线播放 | 天天做夜夜操 | 中文线码中文高清播放中 | 日韩欧美国产一区二区三区四区 | 中国欧美一级毛片免费 | 国产99re在线观看只有精品 | 一级黄色毛片 | 色姑娘综合网 | 狠狠久久亚洲欧美专区 | 免费xxx | 欧美日韩国产亚洲一区二区三区 | 久久免费观看国产精品 | 一级毛片在线视频 | 国产在线精品香蕉综合网一区 | 国产精品一区二区久久不卡 | 国产免费资源 |