日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

[ASP.NET MVC] 利用自定義的AuthenticationFilt

系統(tǒng) 4603 0
原文: [ASP.NET MVC] 利用自定義的AuthenticationFilter實(shí)現(xiàn)Basic認(rèn)證

很多情況下目標(biāo)Action方法都要求在一個(gè)安全上下文中被執(zhí)行,這里所謂的安全上下文主要指的是當(dāng)前請(qǐng)求者是一個(gè)經(jīng)過(guò)授權(quán)的用戶。授權(quán)的本質(zhì)就是讓用戶在他許可的權(quán)限范圍內(nèi)做他能夠做的事情,授權(quán)的前提是請(qǐng)求者是一個(gè)經(jīng)過(guò)認(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”下(其他四種過(guò)濾器接口都定義在“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方法的過(guò)程中設(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í)行的一類過(guò)濾器。所有過(guò)濾器的執(zhí)行都是ActionInvoker來(lái)驅(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í)行之后,通過(guò)本書(shū)第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ì)象將被用來(lái)對(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í)行過(guò)程中對(duì)AuthenticationContext對(duì)象的Principal屬性作了相應(yīng)的設(shè)置,該屬性值將會(huì)作為當(dāng)前HttpContext和當(dāng)前線程的Principal。

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

在ASP.NET MVC的應(yīng)用編程接口中,我們找不到IAuthenticationFilter接口的實(shí)現(xiàn)者。為了讓大家對(duì)這個(gè)在ASP.NET MVC 5才引入的過(guò)濾器具有更加深刻的認(rèn)識(shí),我們接下來(lái)會(huì)通過(guò)一個(gè)實(shí)例來(lái)演示如何通過(guò)自定義的AuthenticationFilter實(shí)現(xiàn)針對(duì)Basic方案的認(rèn)證。不過(guò)在這之前,我們有必要對(duì)Basic這種基本的認(rèn)證方法作一個(gè)基本的了解。Basic和Digest是兩種典型的HTTP認(rèn)證方案。對(duì)于前者,雖然客戶端提供的認(rèn)證憑證(用戶名+密碼)僅僅是被Base64編碼而沒(méi)有被加密,但是我們可以通過(guò)采用HTTPS傳輸利用SSL來(lái)解決機(jī)密性的問(wèn)題,所以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)過(guò)編碼的認(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之前,我們不妨先來(lái)看看使用了這個(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)單起見(jiàn)我們將帳號(hào)采用的用戶名和密碼保存在一個(gè)靜態(tài)字段中。具體的認(rèn)證實(shí)現(xiàn)在實(shí)現(xiàn)的OnAuthentication方法中,我們?cè)谠摲椒ㄖ姓{(diào)用IsAuthenticated判斷請(qǐng)是否經(jīng)過(guò)認(rèn)證,并在認(rèn)證成功的情況下得到代表請(qǐng)求用戶的Principal對(duì)象,然對(duì)作為參數(shù)的AuthenticationContext對(duì)象的Principal屬性進(jìn)行賦值。對(duì)于沒(méi)有經(jīng)過(guò)認(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)求通過(guò)認(rèn)證,并根據(jù)解析出來(lái)的用戶名創(chuàng)建一個(gè)GenericPrincipal對(duì)象作為輸出參數(shù)user的值。如果請(qǐng)求并為通過(guò)認(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)。

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


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

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

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

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

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

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 新建县| 丹阳市| 长武县| 阿鲁科尔沁旗| 蒲江县| 莲花县| 余姚市| 阿图什市| 凯里市| 峨山| 恩平市| 绍兴市| 伊吾县| 康乐县| 永安市| 塘沽区| 湟源县| 宜兴市| 都江堰市| 武穴市| 贵溪市| 资源县| 株洲县| 弥渡县| 沙洋县| 峨眉山市| 吉木萨尔县| 临沭县| 临潭县| 洛川县| 嘉定区| 颍上县| 乐陵市| 农安县| 舞阳县| 隆安县| 泗阳县| 娄烦县| 合阳县| 宁德市| 海伦市|