<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          開放平臺(tái)設(shè)計(jì)方案與實(shí)踐

          共 13585字,需瀏覽 28分鐘

           ·

          2021-05-19 09:12

          點(diǎn)擊上方老周聊架構(gòu)關(guān)注我


          一、背景

          隨著業(yè)務(wù)的發(fā)展,越來越多的系統(tǒng)需要數(shù)據(jù)往來。那對(duì)外提供的接口也越來越多,而且各個(gè)接口散落在不同的項(xiàng)目中被調(diào)用,多了的話排查問題困難且混亂。基于這個(gè)痛點(diǎn),我們有必要打造一套開放平臺(tái)來管理各個(gè) api 的調(diào)用情況。

          二、開放平臺(tái)設(shè)計(jì)

          我們先從整體的功能需求來分析,主要有以下幾點(diǎn):

          • 開發(fā)者身份注冊(cè)與數(shù)據(jù)權(quán)限范圍授權(quán)

          • 開發(fā)者獲取相關(guān)資料(接口文檔、使用說明、對(duì)接人聯(lián)系方式等)

          • 平臺(tái)方接入管理,申請(qǐng)審核流程、服務(wù)配置、服務(wù)管理、參數(shù)配置等

          • 平臺(tái)方運(yùn)營(yíng)管理,業(yè)務(wù)交易管理及統(tǒng)計(jì)報(bào)表分析

          • 安全層面需求,加密、應(yīng)用秘鑰、應(yīng)用接口權(quán)限控制、訪問黑白名單、字段脫敏還原等

          • 性能方面要求,客戶端緩存、服務(wù)端緩存、緩存等


          這里老周給出自己的一個(gè)架構(gòu),大家可以參考下:

          上面的設(shè)計(jì)方案更多的是針對(duì)比較大型的公司,想要把整個(gè)開平的能力建設(shè)完善。但市場(chǎng)上更多的是中小型公司,它們沒有太多的人力去開發(fā)與建設(shè)這么全面的開放平臺(tái)。

          那如果是中小型公司,那它們的開放平臺(tái)如何不費(fèi)很大精力去實(shí)現(xiàn)呢?不管中小型還是大型公司的開放平臺(tái),上面說的那個(gè)圖中其它部分可以省略,但安全機(jī)制是必需的,也就是架構(gòu)圖中的統(tǒng)一鑒權(quán)。試想一下,作為提供給第三方調(diào)用接口的開放平臺(tái),如果安全機(jī)制不能保障,那外部誰都可以來調(diào)用你們公司的內(nèi)部資源,危害可想而知。

          老周下面就來針對(duì)不同的業(yè)務(wù)場(chǎng)景來給出相應(yīng)的開放平臺(tái)安全機(jī)制的保障,也就是根據(jù)不同類型的網(wǎng)站給出相對(duì)應(yīng)的開放平臺(tái)設(shè)計(jì)方案。

          三、小型網(wǎng)站

          3.1 基于 session 的登錄認(rèn)證

          在傳統(tǒng)的用戶登錄認(rèn)證中,因?yàn)?http 是無狀態(tài)的,所以都是采用 session 方式。用戶登錄成功,服務(wù)端會(huì)保存一個(gè) session,當(dāng)然會(huì)給客戶端一個(gè) sessionId,客戶端會(huì)把 sessionId 保存在 cookie 中,每次請(qǐng)求都會(huì)攜帶這個(gè) sessionId。服務(wù)器收到 sessionId,找到前期保存的數(shù)據(jù),由此得知用戶的身份。


          對(duì)于小型網(wǎng)站,特別是單機(jī)系統(tǒng),基于 session 的登錄認(rèn)證方案已經(jīng)夠用了,而且簡(jiǎn)單高效。

          四、中型網(wǎng)站

          隨著用戶量的增多,上面基于 cookie + session 的這種模式缺點(diǎn)就顯現(xiàn)出來了,這種模式通常是保存在內(nèi)存中,而且服務(wù)從單服務(wù)到多服務(wù)會(huì)面臨 session 共享問題,開銷也隨即越來越大。

          那中型網(wǎng)站的安全認(rèn)證機(jī)制是啥呢?接下來 JWT(JSON Web Token) 即將登場(chǎng),關(guān)于 JWT 的概念與原理,老周這里覺得還是有必要說一下。

          4.1 JWT 的概念

          4.1.1 什么是 JWT?

          JWT 是一個(gè)開放的行業(yè)標(biāo)準(zhǔn)(RFC 7519),它定義了一種簡(jiǎn)潔的、自包含的協(xié)議格式,用于在通信雙方傳遞 json 對(duì)象,傳遞的信息經(jīng)過數(shù)字簽名可以被驗(yàn)證和信任。JWT 可以使用 HMAC 算法或使用 RSA的公鑰/私鑰對(duì)來簽名,防止被篡改。

          說白了 JWT 就是一套基于 token 的身份認(rèn)證的方案,可以保證安全傳輸?shù)那疤嵯聜魉鸵恍┗镜男畔ⅲ詼p輕對(duì)外部存儲(chǔ)的依賴,減少了分布式組件的依賴,減少了硬件的資源。

          可實(shí)現(xiàn)無狀態(tài)、分布式的 Web 應(yīng)用授權(quán),JWT 的安全特性保證了 token 的不可偽造和不可篡改。

          本質(zhì)上是一個(gè)獨(dú)立的身份驗(yàn)證令牌,可以包含用戶標(biāo)識(shí)、用戶角色和權(quán)限等信息,以及您可以存儲(chǔ)任何其他信息(自包含)。任何人都可以輕松讀取和解析,并使用密鑰來驗(yàn)證真實(shí)性。

          4.1.2 JWT 令牌結(jié)構(gòu)

          JWT 令牌由三部分組成,每部分中間使用點(diǎn)(.)分隔,比如:xxxxx.yyyyy.zzzzz

          • Header
            頭部包括令牌的類型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA),例如:

            {
                "alg""HS256"
                "typ""JWT"
            }

            將上邊的內(nèi)容使用 Base64Url 編碼,得到一個(gè)字符串就是 JWT 令牌的第一部分。

          • Payload
            第二部分是負(fù)載,內(nèi)容也是一個(gè) json 對(duì)象,它是存放有效信息的地方,它可以存放 jwt 提供的現(xiàn)成字段,比如:iss(簽發(fā)者),exp(過期時(shí)間戳),sub(面向的用戶)等,也可自定義字段。此部分不建議存放敏感信息,因?yàn)榇瞬糠挚梢越獯a還原原始內(nèi)容。最后將第二部分負(fù)載使用 Base64Url 編碼,得到一個(gè)字符串就是 JWT 令牌的第二部分。一個(gè)例子:

            {
                "sub""1234567890"
                "name""微信公眾號(hào)【老周料架構(gòu)】"
                "iat"1516239022
            }
          • Signature
            第三部分是簽名,此部分用于防止 jwt 內(nèi)容被篡改。這個(gè)部分使用 base64url 將前兩部分進(jìn)行編碼,編碼后使用點(diǎn)(.)連接組成字符串,最后使用 header 中聲明簽名算法進(jìn)行簽名。
            secret:簽名所使用的密鑰。

            HMACSHA256 ( 
                base64UrlEncode(header) + "." + base64UrlEncode(payload), secret
            )

            驗(yàn)簽過程描述:獲取 token 值,讀取 Header 部分并 Base64 解碼,得到簽名算法。根據(jù)以上方法算出簽名,如果簽名信息不一致,說明是非法的。

          4.2 JWT 的流程



          4.3 JWT 代碼案例

          如果你們公司有第三方應(yīng)用接入的開放平臺(tái),那可以在里面走相應(yīng)的接入流程得到 appId 和 appSecret。如果沒有的話,那可以簡(jiǎn)單點(diǎn)與第三方約定相應(yīng)的 appId 和 appSecret。老周這里假設(shè)你們已經(jīng)約定好了,我這里直接放在請(qǐng)求頭里來獲取 token,還有其它的方式,比如放在請(qǐng)求參數(shù)或者 cookie 里。

          4.3.1 maven 依賴

          <dependency>
              <groupId>com.auth0</groupId>
              <artifactId>java-jwt</artifactId>
              <version>3.4.1</version>
          </dependency>

          4.3.2 JWTUtil 工具類

          public class JWTUtil {
              private static String SECRETE = "default_secrete";
              private static String APP_ID = "zhifubao";
              private static String APP_SECRETE = "123abc";

              /**
               * 傳入 appId、appSecret 進(jìn)行驗(yàn)證
               * @param appId 應(yīng)用id
               * @param appSecret 應(yīng)用密鑰
               * @return 返回一個(gè)加密 JWT token
               */

              public static String getToken(String appId, String appSecret) {
                  String token = JWT.create()
                          // 存放 payload 數(shù)據(jù)
                          .withClaim("appId", appId)
                          .withClaim("appSecret", appSecret)
                          // 使用 SECRETE 對(duì)稱加密生成 signature
                          .sign(Algorithm.HMAC256(SECRETE));
                  return token;
              }

              /**
               * 驗(yàn)證 token
               * @param token
               * @return
               */

              public static boolean verifyToken(String token) {
                  HashMap<String, String> map = new HashMap<>();
                  // 通過 SECRETE 和相同的對(duì)稱加密算法反加密
                  DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SECRETE))
                          .build().verify(token);
                  // 獲得你儲(chǔ)存的 payload 信息
                  String appId = jwt.getClaim("appId").asString();
                  String appSecret = jwt.getClaim("appSecret").asString();
                  if (APP_ID.equals(appId) && APP_SECRETE.equals(appSecret)) {
                      return true;
                  }
                  return false;
              }
          }

          4.3.3 JWTController 類

          @RestController
          public class JWTController {
              @RequestMapping("/getToken")
              public String getToken(@RequestHeader("appId") String appId, @RequestHeader("appSecret") String appSecret) {
                  return JWTUtil.getToken(appId, appSecret);
              }
          }

          4.3.4 測(cè)試


          拓展:這個(gè)私鑰 secrete 是固定的,為了加強(qiáng)安全,你甚至可以使用動(dòng)態(tài)的 secrete 私鑰,
          例如:動(dòng)態(tài)私鑰 = 靜態(tài)私鑰 + 用戶的 ip,這樣即使別人得到了用戶的 token,也會(huì)因?yàn)?ip 不一致而訪問失敗。

          拿到了應(yīng)用資源服務(wù)器的 token 令牌了,那我們拿這個(gè)令牌去訪問相應(yīng)的資源看看。

          @RequestMapping("/getResource")
          public String getResource(String resourceId) {
              return resourceId + " 資源獲取成功";
          }

          簡(jiǎn)單模擬一個(gè)請(qǐng)求,直接返回該資源獲取成功。我們接下來就用 postman 工具來模擬一下這個(gè)資源服務(wù)器的這個(gè)接口請(qǐng)求。



          認(rèn)證失敗了,這是因?yàn)槲覀儧]有在請(qǐng)求頭里填剛剛獲取的 token。我們把通過調(diào)用 getToken 接口獲取的 token 值放在在請(qǐng)求頭,然后認(rèn)證通過,獲取到了資源服務(wù)器的資源。



          4.3.5 繼續(xù)追問

          這里你有可能問了,老周,這里咋就帶上 token 在請(qǐng)求頭就可以獲取到了資源服務(wù)器的資源啊。

          我把代碼貼出來,你一看就知道了。

          這里寫了一個(gè) token 的攔截器,對(duì)請(qǐng)求頭的 token 進(jìn)行驗(yàn)簽,通過才放行。

          @Component
          public class TokenInterceptor implements HandlerInterceptor {
              @Override
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                  String token = request.getHeader("token");
                  if (token != null) {
                      boolean result = JWTUtil.verifyToken(token);
                      if (result) {
                          System.out.println("通過攔截器");
                          return true;
                      }
                  }

                  response.setCharacterEncoding("UTF-8");
                  response.setContentType("application/json; charset=utf-8");
                  try{
                      response.getWriter().append("認(rèn)證失敗,無效的token令牌!");
                      System.out.println("認(rèn)證失敗,無效的token令牌!");
                  } catch (Exception e) {
                      e.printStackTrace();
                      response.sendError(500);
                      return false;
                  }
                  return false;
              }
          }

          這里有個(gè)攔截器配置類,把需要攔截的 api 路徑放進(jìn)來,然后會(huì)對(duì)某個(gè) api 進(jìn)行細(xì)粒度的管控。

          @Configuration
          public class IntercepterConfig implements WebMvcConfigurer {
              private TokenInterceptor tokenInterceptor;

              public IntercepterConfig(TokenInterceptor tokenInterceptor){
                  this.tokenInterceptor = tokenInterceptor;
              }

              @Override
              public void addInterceptors(InterceptorRegistry registry) {
                  List<String> excludePath = new ArrayList<>();
                  excludePath.add("/getResource/");
                  excludePath.add("/static/**");  //靜態(tài)資源
                  registry.addInterceptor(tokenInterceptor)
                          .addPathPatterns("/**")
                          .excludePathPatterns(excludePath);
                  WebMvcConfigurer.super.addInterceptors(registry);
              }
          }

          這就實(shí)現(xiàn)中型網(wǎng)站安全認(rèn)證機(jī)制了,細(xì)心的讀者可能會(huì)發(fā)現(xiàn),這個(gè) token 是固定的,會(huì)存在一些不安全。是的,我上面也說了,可以用動(dòng)態(tài)的 secrete 私鑰或者 token 過期機(jī)制來繼續(xù)保證更高的安全性。

          五、大型網(wǎng)站

          大型網(wǎng)站的話,針對(duì)中型網(wǎng)站的方案就不太可行了,為什么呢?由于大型網(wǎng)站的請(qǐng)求流量很大,而 token 由于自包含信息,因此一般數(shù)據(jù)量較大,而且每次請(qǐng)求都需要傳遞,因此比較占帶寬。另外,token 的簽名驗(yàn)簽操作也會(huì)給 cpu 帶來額外的處理負(fù)擔(dān)。可以采用微服務(wù)統(tǒng)一認(rèn)證方案 Spring Cloud OAuth2,那什么情況下需要使用 OAuth2?

          • 第三方授權(quán)登錄的場(chǎng)景:比如,我們經(jīng)常登錄一些網(wǎng)站或者應(yīng)用的時(shí)候,可以選擇使用第三方授權(quán)登錄的方式,比如:微信授權(quán)登錄、QQ授權(quán)登錄、微博授權(quán)登錄等,這是典型的 OAuth2 使用場(chǎng)景。

          • 單點(diǎn)登錄的場(chǎng)景:如果項(xiàng)目中有很多微服務(wù)或者公司內(nèi)部有很多服務(wù),可以專?做一個(gè)認(rèn)證中心(充當(dāng)認(rèn)證平臺(tái)?色),所有的服務(wù)都要到這個(gè)認(rèn)證中心做認(rèn)證,只做一次登錄,就可以在多個(gè)授權(quán)范圍內(nèi)的服務(wù)中自由串行。

          5.1 OAuth2 構(gòu)建微服務(wù)統(tǒng)一認(rèn)證服務(wù)思路


          注意:在我們統(tǒng)一認(rèn)證的場(chǎng)景中,Resource Server 其實(shí)就是我們的各種受保護(hù)的微服務(wù),微服務(wù)中的 各種 API 訪問接口就是資源,發(fā)起 http 請(qǐng)求的瀏覽器就是 Client 客戶端(對(duì)應(yīng)為第三方應(yīng)用)。

          5.1.1 搭建認(rèn)證服務(wù)器(Authorization Server)

          5.1.1.1 maven 依賴文件


          5.1.1.2 application.yml 文件



          5.1.1.3 OauthServerApplication9999 啟動(dòng)類


          5.1.1.4 認(rèn)證服務(wù)器配置類


          5.1.1.5 認(rèn)證服務(wù)器安全配置類



          5.1.1.6 測(cè)試

          5.1.1.6.1 獲取 token

          http://localhost:9999/oauth/token?client_secret=abcxyz&grant_type=password&username=admin&password=123456&client_id=client_riemann

          endpoint:/oauth/token

          獲取token攜帶的參數(shù)
          client_id:客戶端id
          client_secret:客戶單密碼
          grant_type:指定使用哪種頒發(fā)類型,password
          username:用戶名
          password:密碼



          5.1.1.6.2 校驗(yàn) token

          http://localhost:9999/oauth/check_token?token=28317df7-4036-4bbb-8bb3-12f71fa07802


          如果出現(xiàn)以上頁(yè)面,表明 token 過期了,設(shè)置的是 20s。所以要在 20s 以內(nèi)校驗(yàn)才會(huì)生效。

          下面才是 token 校驗(yàn)成功的效果:


          5.1.1.6.3 刷新 token

          http://localhost:9999/oauth/token?grant_type=refresh_token&client_id=client_riemann&client_secret=abcxyz&refresh_token=68582d02-3a1d-4c31-ae22-ac7e84824d0d



          5.1.2 搭建資源服務(wù)器(希望訪問被認(rèn)證的微服務(wù))

          5.1.2.1 資源服務(wù) Resource Server 配置類


          5.1.2.2 測(cè)試





          此測(cè)試結(jié)果也印證了代碼的效果



          我們加上帶上token測(cè)下看看:


          5.2 OAuth2 統(tǒng)一認(rèn)證服務(wù)思考

          • 當(dāng)我們第一次登陸之后,認(rèn)證服務(wù)器頒發(fā) token 并將其存儲(chǔ)在認(rèn)證服務(wù)器中,后期我們 訪問資源服務(wù)器時(shí)會(huì)攜帶 token,資源服務(wù)器會(huì)請(qǐng)求認(rèn)證服務(wù)器驗(yàn)證 token 有效性,如果資源服務(wù)器有很多,那么認(rèn)證服務(wù)器壓力會(huì)很大。

          • 另外,資源服務(wù)器向認(rèn)證服務(wù)器 check_token,獲取的也是用戶信息 UserInfo,能否把用戶信息存儲(chǔ)到令牌中,讓客戶端一直持有這個(gè)令牌,令牌的驗(yàn)證也在資源服務(wù)器進(jìn)行,這樣避免和認(rèn)證服務(wù)器頻繁的交互。

          • 我們可以考慮使用 JWT 進(jìn)行改造,使用 JWT 機(jī)制之后資源服務(wù)器不需要訪問認(rèn)證服務(wù)器。

          5.3 JWT 改造統(tǒng)一認(rèn)證授權(quán)中心的令牌存儲(chǔ)機(jī)制

          JWT 在上面中型網(wǎng)站那一節(jié)說過了,這里就不重復(fù)說了,老周直接上代碼了。

          5.3.1 認(rèn)證服務(wù)器端 JWT 改造(改造主配置類)


          5.3.2 修改 JWT 令牌服務(wù)方法



          5.3.3 認(rèn)證服務(wù)器端測(cè)試


          可以看出,使用 jwt 令牌生成的 access_token 和上一篇的不一樣。

          我們用這個(gè)網(wǎng)站:https://jwt.io/#encoded-jwt 把該 access_token 進(jìn)行解碼,解碼如下:



          其他兩個(gè)驗(yàn)證 token、刷新 token 跟上一篇類似。

          5.3.4 資源服務(wù)器校驗(yàn) JWT 令牌

          不需要和遠(yuǎn)程認(rèn)證服務(wù)器交互,添加本地 tokenStore。



          5.3.5 源服務(wù)器端測(cè)試



          這樣就完成了資源服務(wù)根據(jù)事先約定的算法自行完成令牌校驗(yàn),無需每次都請(qǐng)求認(rèn)證服務(wù)完成授權(quán)。

          六、總結(jié)

          老周首先從開放平臺(tái)的整體功能設(shè)計(jì)來分析了有如下幾個(gè)要點(diǎn):開發(fā)者認(rèn)證、開放平臺(tái)內(nèi)部管理系統(tǒng)、安全機(jī)制以及性能。

          但考慮很多公司它們沒有太多的人力去開發(fā)與建設(shè)這么全面的開放平臺(tái),故抓住其中的最核心的一點(diǎn),那就是安全機(jī)制。

          針對(duì)于安全機(jī)制來說,不同類型的網(wǎng)站有不同的安全機(jī)制保障。

          • 小型網(wǎng)站:基于 session 的登錄認(rèn)證,在小型網(wǎng)站特別是單機(jī)系統(tǒng),這種方案夠用了,而且簡(jiǎn)單高效;

          • 中型網(wǎng)站:到了中型網(wǎng)站,服務(wù)肯定是分布式部署的,這個(gè)時(shí)候小型網(wǎng)站中基于 session 的登錄認(rèn)證方案的缺點(diǎn)就暴露出來了。每個(gè)應(yīng)用服務(wù)都需要在 session 中存儲(chǔ)用戶身份信息,通過負(fù)載均衡將本地的請(qǐng)求分配到另一個(gè)應(yīng)用服務(wù)需要將 session 信息帶過去,否則會(huì)重新認(rèn)證。我們還要通過 session 共享、session 黏貼等方案來解決。從而引入了第三方分布式組件,比如 redis,增加了系統(tǒng)的復(fù)雜性。并且 session 方案還有另一個(gè)缺點(diǎn),比如基于 cookie,移動(dòng)端不能有效使用等。所以中型網(wǎng)站的話基于 JWT 的 token 認(rèn)證機(jī)制,服務(wù)端不用存儲(chǔ)認(rèn)證數(shù)據(jù),易維護(hù)擴(kuò)展性強(qiáng),客戶端可以把 token 存在任意地方,并且可以實(shí)現(xiàn) web 和 app 統(tǒng)一認(rèn)證機(jī)制。

          • 大型網(wǎng)站:到了大型網(wǎng)站,請(qǐng)求量也隨之暴漲,中型網(wǎng)站的 token 認(rèn)證機(jī)制的缺點(diǎn)也逐步暴露出來了,token 由于自包含信息,因此 一般數(shù)據(jù)量較大,而且每次請(qǐng)求都需要傳遞,因此比較占帶寬。另外,token 的簽名驗(yàn)簽操作也會(huì)給 cpu 帶來額外的處理負(fù)擔(dān)。這個(gè)時(shí)候得采用微服務(wù)統(tǒng)一認(rèn)證方案 Spring Cloud OAuth2,后面我們又對(duì) OAuth2 進(jìn)行了一些優(yōu)化,因?yàn)榇笮途W(wǎng)站的開平請(qǐng)求流量會(huì)很大,資源服務(wù)器會(huì)請(qǐng)求認(rèn)證服務(wù)器驗(yàn)證 token 有效性,那么認(rèn)證服務(wù)器壓力會(huì)很大。另外,資源服務(wù)器向認(rèn)證服務(wù)器 check_token,獲取的也是用戶信息 UserInfo,能否把用戶信息存儲(chǔ)到令牌中,讓客戶端一直持有這個(gè)令牌,令牌的驗(yàn)證也在資源服務(wù)器進(jìn)行,這樣避免和認(rèn)證服務(wù)器頻繁的交互。所以我們后續(xù)使用 JWT 進(jìn)行改造,使用 JWT 機(jī)制之后資源服務(wù)器不需要訪問認(rèn)證服務(wù)器。性能以及安全機(jī)制都得到了有力保障。


          歡迎大家關(guān)注我的公眾號(hào)【老周聊架構(gòu)】,Java后端主流技術(shù)棧的原理、源碼分析、架構(gòu)以及各種互聯(lián)網(wǎng)高并發(fā)、高性能、高可用的解決方案。

          喜歡的話,點(diǎn)贊、再看、分享三連。

          點(diǎn)個(gè)在看你最好看



          瀏覽 142
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  豆花视频在线观看国产豆花 | 久久电影国产 | 亚洲色婷婷久久精品AV蜜桃 | 亚洲精品久久久日产欧美蜜桃 | 午夜日韩在线 |