【问题标题】:having an issue with membership credential verification failed when it shouldn't be using it会员凭证验证出现问题,但不应该使用它却失败了
【发布时间】:2014-01-07 04:59:04
【问题描述】:

由于我们的网站无法直接使用信用卡,因此我们正在将带有凭据和其他杂项变量的用户路由到另一个网站上的“托管页面”。

更详细地说,这是用户通常如何访问它:

  1. 访问我们的网站并使用他们之前创建的用户名和密码登录。这使用了 asp.net 成员资格提供程序。

  2. 登录后,我们会向他们显示他们的帐户,并且他们有一个付款按钮。一旦他们点击这个...

  3. 他们会被提示“预付款”页面以验证金额和其他各种信息。他们从这里点击继续...

  4. 因此,付款页面显示在我们网站的 iframe 中。我们使用以下代码将它们重定向到外部托管网页:

  5. 一旦进入支付页面并且客户点击提交,该网站就会向我们的网站提交一个帖子,并返回他们开始的网站并传回有关收费的信息。我获取此信息并将其保存到我们的数据库并显示收据。

除了#5,一切都很好。这在大多数情况下都有效,但大约十分之一的人会返回此消息:

Event code: 4006 
Event message: Membership credential verification failed. 
Event time: 12/16/2013 4:32:22 AM 
Event time (UTC): 12/16/2013 12:32:22 PM 
Event ID: 42c509f2a25d46f0af17e72a52dfbbe5 
Event sequence: 38 
Event occurrence: 1 
Event detail code: 0 

Application information: 
    Application domain: /LM/W3SVC/3/ROOT/SuburbanCustPortal-1-130316693110399868 
    Trust level: Full 
    Application Virtual Path: /SuburbanCustPortal 
    Application Path: C:\inetpub\wp\SuburbanCustPortal\ 
    Machine name: WIN-OB929P97YAR 

Process information: 
    Process ID: 3620 
    Process name: w3wp.exe 
    Account name: NT AUTHORITY\NETWORK SERVICE 

Request information: 
    Request URL: https://myurl:443/SuburbanCustPortal/Account/Logon2 
    Request path: /SuburbanCustPortal/Account/Logon2 
    User host address: xx.xx.xx.xx 
    User:  
    Is authenticated: False 
    Authentication Type:  
    Thread account name: NT AUTHORITY\NETWORK SERVICE 

Name to authenticate: testuser 

我无法在我运行的少数测试用例上发生这种情况,这让我更加沮丧。

这是我的 web.config:

<?xml version="1.0"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->
<configuration>

  <appSettings>
    <add key="webpages:Version" value="1.0.0.0"/>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
    <add key="suburbanServiceUrl" value=""/>
  </appSettings>

  <system.web>

    <sessionState
      mode="InProc"
      stateConnectionString="tcpip=127.0.0.1:42424"
      stateNetworkTimeout="60"
      sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI"
      cookieless="false"
      timeout="60"
    />

    <customErrors mode="Off"/>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      </assemblies>
    </compilation>
    <authentication mode="Forms">
      <!-- timeout: Gets and sets the amount of time, in minutes, allowed between requests
                    before the session-state provider terminates the session. -->
      <forms loginUrl="~/Account/LogOn" timeout="60"/>
    </authentication>

    <membership>
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider"
             type="System.Web.Security.SqlMembershipProvider"
             connectionStringName="ApplicationServices"
             enablePasswordRetrieval="false"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="false"
             requiresUniqueEmail="true"
             maxInvalidPasswordAttempts="30"
             minRequiredPasswordLength="6"
             minRequiredNonalphanumericCharacters="0"
             passwordAttemptWindow="10"
             applicationName="webportal"/>
      </providers>

    </membership>

    <profile>
      <providers>
        <clear/>
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
      </providers>
    </profile>

    <roleManager enabled="true">
      <providers>
        <clear/>
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/"/>
        <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/"/>
      </providers>
    </roleManager>

    <pages enableSessionState="true">
      <namespaces>
        <add namespace="System.Web.Helpers"/>
        <add namespace="System.Web.Mvc"/>
        <add namespace="System.Web.Mvc.Ajax"/>
        <add namespace="System.Web.Mvc.Html"/>
        <add namespace="System.Web.Routing"/>
        <add namespace="System.Web.WebPages"/>
      </namespaces>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="Session"/>
      <add name="Session" type="System.Web.SessionState.SessionStateModule"/>
    </modules>
    <httpProtocol>
    </httpProtocol>
    <staticContent>
      <clientCache cacheControlCustom="public"
      cacheControlMaxAge="00:00:01" cacheControlMode="UseMaxAge" />
    </staticContent>   
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_ISuburbanService" maxReceivedMessageSize="128072" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:2181/ISuburbanService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISuburbanService"
        contract="SuburbanService.ISuburbanService" name="BasicHttpBinding_ISuburbanService" />
    </client>
    <!--<bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_ISuburbanService" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="Transport">
            <transport clientCredentialType="Basic" proxyCredentialType="None"
              realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://localhost/SuburbanHUB/ISuburbanService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISuburbanService"
        contract="SuburbanService.ISuburbanService" name="BasicHttpBinding_ISuburbanService" />
    </client>-->
    <!--<behaviors>
      <serviceBehaviors>
        <behavior name="SomeServiceServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>-->
  </system.serviceModel>
</configuration>

以及捕获帖子的方法:

  [NoCache]
    [HttpPost]
    public ActionResult Receipt(string id)
    {
      var sb = new StringBuilder();
      try
      {
        sb.AppendLine("ActionResult Reciept(string account)");

        var count = 0;
        var postVals = new Dictionary<string, string>();
        foreach (var key in Request.Form.AllKeys)
        {
          sb.AppendLine("count: " + count);
          sb.AppendLine(string.Format("key:   {0}    Value:   {1}", key, Request.Form[key]));
          postVals.Add(key, Request.Form[key]);
          sb.AppendLine("finished count: " + count);
          count++;
        }
        sb.AppendLine("finished processing ALLKeys");
        var paymentReq = createPaymentRequest(postVals);
        sb.AppendLine("finished processing 'var paymentReq = createPaymentRequest(postVals)' ");
        var receipt = _client.RecordPaymentWithRequest(paymentReq);

        var retval = PartialView(receipt.Duplicate ? "Duplicate Receipt" : "Receipt", receipt);
        sb.AppendLine(string.Format("retval: {0}", retval));
        return retval;

      }
      catch (Exception ex)
      {
        sb.AppendLine(string.Format("Receipt error: {0}", ex.Message));
        Logging.LogException("Receipt error!", ex, _asName);
        throw;
      }
      finally
      {
        Logging.LogInfo(sb.ToString(), _asName);
      }
    }

正如您在上面看到的,我没有[Authorize],因此它不应该要求会员提供者检查访问权限。班级水平也没有。

有人对可能发生的事情有任何建议吗?

更新

2013-12-16 04:22:14 xxx.xxx.xxx.xxx GET /SuburbanCustPortal/Scripts/Views/logon.js - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 304 0 0 109
2013-12-16 04:22:14 xxx.xxx.xxx.xxx GET /SuburbanCustPortal/Content/images/mod/modavoca.png - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 304 0 0 93
2013-12-16 04:22:15 xxx.xxx.xxx.xxx GET /Content/favicon.ico - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 404 0 2 250
2013-12-16 04:22:15 xxx.xxx.xxx.xxx GET /apple-touch-icon-precomposed.png - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 404 0 2 250
2013-12-16 04:22:15 xxx.xxx.xxx.xxx GET /apple-touch-icon.png - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 404 0 2 78
#Software: Microsoft Internet Information Services 7.0
#Version: 1.0
#Date: 2013-12-16 04:39:52
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken
2013-12-16 04:39:52 xxx.xxx.xxx.xxx GET / - 443 - xxx.xxx.xxx.xxx - 200 0 0 171
2013-12-16 04:50:12 xxx.xxx.xxx.xxx POST /SuburbanHUB/ISuburbanService.svc - 443 suburbansoftware xxx.xxx.xxx.xxx - 200 0 0 875
2013-12-16 04:50:12 xxx.xxx.xxx.xxx POST /SuburbanHUB/ISuburbanService.svc - 443 suburbansoftware xxx.xxx.xxx.xxx - 200 0 0 187
2013-12-16 04:50:12 xxx.xxx.xxx.xxx GET /SuburbanCustPortal/Account/Verify id=dde4bbfb-0d2e-4706-a604-36eea3fdcae3&verifyid=c0b4fdb5-9bb3-4d2b-b724-df42e6ea2a59 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(iPhone;+CPU+iPhone+OS+7_0_3+like+Mac+OS+X)+AppleWebKit/537.51.1+(KHTML,+like+Gecko)+Version/7.0+Mobile/11B511+Safari/9537.53 200 0 0 1328
2013-12-16 04:50:12 xxx.xxx.xxx.xxx GET /SuburbanCustPortal/Content/reset.css - 443 - xxx.xxx.xxx.xxxMozilla/5.0+(iPhone;+CPU+iPhone+OS+7_0_3+like+Mac+OS+X)+AppleWebKit/537.51.1+(KHTML,+like+Gecko)+Version/7.0+Mobile/11B511+Safari/9537.53 200 0 0 453

从 04:22:15 到 04:39:52 的日志中有一个间隔

这正常吗?

编辑

我为那些询问的人澄清了上述步骤。

【问题讨论】:

  • 您有这些请求的 IIS 日志吗?事件日志看起来特别是正在请求该页面,这意味着某些内容正在重定向到该页面。日志会显示在它之前请求了哪个页面。
  • @MatthewSteeples 我会检查并发布结果。
  • 您可能只需要丢弃一些 Logging.LogInfo 行,以尝试缩小错误发生的范围。恶心,我知道,但在这种情况下,它是有效的。
  • 有件事困扰着我。 Receipt 操作似乎不以任何方式授权 POST。它似乎很容易被滥用。是我遗漏了什么还是您的设计缺乏适当的安全性?
  • 这些澄清细节应酌情添加到问题或答案中; cmets 可以随时被删除。

标签: c# asp.net asp.net-mvc membership-provider


【解决方案1】:

当时发生的事情非常可疑。

我同意,但似乎在第 4 步中您重定向了站点,然后用户进行了数据输入。如果用户偶尔需要 10 到 20 分钟来输入该信息(由于分心等),这比只是简单的竞争条件更有可能。

如果您仍然拥有所有错误的数据,您可以回顾一下是否可以找到发生这种情况的时间(或每 xx 小时 - 见下文)的模式。

  1. 检查您的 IIS 设置以查看应用程序池何时回收。它每晚凌晨4点左右回收吗?是否按滚动时间表进行?默认情况下,IIS 出于某种原因会在奇数小时内回收(我认为每 28 小时一次)。
  2. 退出 InProc 会话状态并进入状态服务器(或 SQL)。从长远来看,InProc 只会给你带来痛苦。请注意,当您进行此更改时,您必须确保您放入会话中的所有对象都是可序列化的,否则您将得到错误。 InProc 不需要在会话中序列化对象。

编辑: 好的,检查您的应用程序池回收:

  1. 在 IIS 管理器中,选择相应的应用程序池并选择高级设置(右键单击或使用右侧菜单)。
  2. 滚动到底部的回收部分
  3. 常规时间间隔将每 xx 分钟重置一次应用程序池。默认值为 1740 分钟,或每 29 小时一次。
  4. “特定时间”设置允许您设置计划的回收时间。

一般来说,您确实希望定期(可能每天)回收应用程序池。

回答你的第二个问题:如果确实是这个原因,不是超时问题;这是一个问题,即应用程序池是否在它们被重定向离开和被重定向回来之间的时间段内回收。将会话状态更改为 InProc 以外的其他内容应该可以解决此问题。

也就是说,会话到期也可能是导致此问题的原因,因此将会话超时设置为更大的值也可以解决此问题。

如果您在发生这种情况的时间段内更广泛地查看日志,它可能会为正在发生的事情提供更多线索。

编辑#2

查看您是否可以在日志中隔离错误的出现。如果可以,请查看正在使用的浏览器是否存在模式。我也会寻找其他模式,看看是否有什么跳出来。

您可能只是使用一堆不同的浏览器(包括移动设备)进行测试,看看您是否可以重现。另外,请尝试不同版本的 IE 和 IE 上的不同安全设置。

【讨论】:

  • 介意指出我在哪里发现池何时在 IIS 中回收?这有必要经常运行吗?
  • 另外,如果他们确实按照建议在重定向页面上停留 10-20 分钟,我是否应该延长超时期限?
  • 您是否有机会在 Global ASAX postAuthenticaton 事件中使用逻辑。你确定你的逻辑不假设以下步骤的相同线程。当使用静态 POST 身份验证时,我看到了非常相似的问题。
  • 似乎每次都会失败,对吧?不只是 10 次中的 1 次?
  • @PhilSandler 很棒的帖子。我会在早上检查这些设置。感谢大家的意见。
【解决方案2】:

请参考以下ScottGuhttp://weblogs.asp.net/scottgu/archive/2006/04/22/Always-set-the-_2200_applicationName_2200_-property-when-configuring-ASP.NET-2.0-Membership-and-other-Providers.aspx的文章。

此外,请确保“aspnet_Applications”数据库表中的“ApplicationName”值和 web.config 中所有提供程序(成员资格提供程序、角色提供程序、配置文件提供程序等)的“applicationName”属性值必须相同再次仔细评估。

希望这能解决您的问题!

【讨论】:

    【解决方案3】:

    我在您的 web.config 中发现的几件事是 -

    1. 您有多个 applicationName。通常,如果 applicationName 不同,IsUserInRoleGetRolesForUser 应该会失败。

    2. 此外,您希望为每个提供程序设置 defaultProvider,尤其是当您有多个提供程序时,例如 roleManager - &lt;roleManager ... defaultProvider="DefaultRoleProvider"&gt;

    当前的 Web.config

    <membership>
       <providers>
          <clear/>
              <add ... applicationName="webportal"/>
       </providers>
    </membership>
    
    <profile>
       <providers>
          <clear/>
          <add ... applicationName="/"/>
        </providers>
    </profile>
    
    <roleManager enabled="true">
       <providers>
          <clear/>
          <add ... applicationName="/"/>
          <add ...  applicationName="/"/>
       </providers>
    </roleManager>
    

    查看 Scott Hanselman 的 ASP.NET Universal Providers 博客的 web.config。

    <sessionState
       mode="InProc"
       stateConnectionString="tcpip=127.0.0.1:42424"
       stateNetworkTimeout="60"
       sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI"
       cookieless="false"
       timeout="60"
    />
    

    InProc 不需要 stateConnectionStringstateNetworkTimeoutsqlConnectionString。更多信息here

    【讨论】:

      【解决方案4】:

      我已经有一段时间没有解决这样的问题了(但我是在 7 年前为 pss 解决的)。

      @PhilSandler 推荐的一切都很好。但是,我有直觉认为根本原因不是 AppPool 回收或会话超时,如果您确实感到绝望,可以尝试Out-Of-Process Session State

      我在想,如果大约 10 个用户中有 1 个出现断断续续的现象(因为您无法重现它),那么它可能是浏览器特定的设置。 我猜遇到问题的用户在他们的浏览器中禁用了 cookie(FF 和 Chrome 用户比普通 IE 用户更频繁地打开)。

      这个假设会稍微符合@SilverlightFox 的理论:

      阻止 3rd 方 cookie 的框架集


      <authentication mode="Forms">
      

      我认为表单身份验证无法在客户端存储会话数据。 会员凭证验证失败事件日志条目可能是由于禁用 cookie 造成的。

      请在 FF 或 Chrome 中禁用 cookie 并尝试我的假设。手指交叉这可以让你重现它。

      【讨论】:

      • 我会在早上试一试。谢谢你的想法。
      • 如果这不是根本原因,请告诉我,即使赏金已经获得,我也有兴趣关注这个问题。
      • 我对此进行了测试,如果没有我的 catch all error 方法抓住它,用户就无法通过登录屏幕。我尝试了几种 cookie 设置的变体。我确实发现我不想再使用它们了 :) 我现在要完全移除它们,因为它会导致我的网站出现问题。
      【解决方案5】:

      浏览网络后,我找到了人们遇到您的 4006 错误并最终解决问题的解决方案。

      • applicationName 字段设置为“/”。 - 这是关于您的问题的最常见的对话。但是,您的 applicationName 字段看起来不错,所以绝对不是这样。

      • ActiveDirectoryMembershipProvider 出现问题 - Link。这似乎不太可能是您的问题,因为您使用的是 SqlMembershipProvider

      • Internet 用户缺少对 .mdf 和 .ldf 文件的权限 - Link。我看到的对这个问题的引用是与使用 SQLExpress 的人有关,因为它在 ASP.NET 用户帐户下运行并且需要读/写访问权限。同样,这似乎不太可能是您的问题,因为您只是间歇性地遇到它。但它与4006错误有关,因此验证用户的权限似乎值得一看。

      • 重复的用户密码 - 我没有保存链接,但如果您对数据库中的用户名和密码都没有唯一限制,它可以返回 4006 响应。所以,到目前为止,这似乎也是我最有可能的,因为它可以解释间歇性行为,并且因为人们在使用互联网时经常双击。我会仔细检查您的限制。

      我很乐意看看我还能找到什么,但首先排除最后两个似乎是个好主意。此外,关于日志间隙最奇怪的一点是,EventLog 数据显示错误几乎发生在 IIS 间隙的中间。然后在它恢复之后,还有另一个日志间隙。看起来可能是两个完全不同的用户。也许不是,只是把它扔在那里。让我知道。祝你好运。

      【讨论】:

      • 我可以看到 OP 没有否决这篇文章。在赏金中获得 2 票或更多票意味着即使您没有帮助 OP,您也会获得奖励。为什么有人会否决一个明确试图排除并询问手头未提及的问题的可能原因的回应。而且,没有给出拒绝投票的理由?嗯,我想知道。
      • 我没有在这个线程上投反对票。这是很好的信息 +1 的帮助!
      【解决方案6】:

      我注意到 src 在 IFrame 上的设置不正确。

      <div align="center"> <iframe width="100%" height="600px" src="@Html.Raw(@ViewBag.GateWayWebsite)"></iframe></div>
      

      GateWayWebsite 应该是正确的 HTML 编码,以防它包含相关但未正确传递的特殊字符:

      <div align="center"> <iframe width="100%" height="600px" src="@ViewBag.GateWayWebsite"></iframe></div>
      

      另一个想法是,可能是阻止 3rd 方 cookie 的框架集 - browser settingP3P privacy policy header。尝试打开 IFrame 外部的链接(即地址栏更改为外部站点),以测试这是否能解决您的问题。

      编辑:我不应该编辑我的答案,因为您现在已经恢复了您的投票。我的回答在技术上是正确的,虽然它可能不是解决你当前问题的答案,但我是正确的,因为你没有对它进行 HTML 编码,所以 URL 的输出是错误的。我发现最好修复所有问题,因为这样可以减少将来出现难以调试的小错误的机会。

      【讨论】:

      • 如果没有 iframe 的 html.raw,viewbag 将无法工作。它通过将 url 放置在适当的位置,否则它将显示为文本。
      • @ErocM:我不确定你的意思...@ViewBag.GateWayWebsite 将由 Razor 引擎呈现。你有一个例子GateWayWebsite URL吗?
      猜你喜欢
      • 1970-01-01
      • 2018-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-09
      • 2021-01-29
      • 1970-01-01
      • 2017-12-18
      相关资源
      最近更新 更多