【问题标题】:how can i automate calling a url on a password protected asp.net-mvc site如何在受密码保护的 asp.net-mvc 站点上自动调用 url
【发布时间】:2011-12-07 20:58:30
【问题描述】:

我有一个带有 sqlserver 后端的 asp.net-mvc 站点,我正在使用 membersprovider 进行登录等。

我有一些自动化的事情,我想每天或每周运行一次,因为我今天可以这样做,如果我:

  1. 登录
  2. 调用网址

所以假设 URL 是

www.mysite.com/MyController/RunCleanupScript

我知道有些人会建议将 RunCleanupScript 的代码分解为网站外部的独立脚本,但我想看看是否有解决方案可以自动等效于手动登录,然后输入此 url 以调用此脚本?

【问题讨论】:

  • 创建一个需要isAuthenticated || isLocal 的过滤器并在本地调用RunCleanupScript
  • 我过去做过的一件事是创建一个“AuthoriseBasic”属性,而不是使用 ASP.NET 的授权属性。然后,您可以使用登录请求的基本凭据通过 .NET WebRequest 登录。这比尝试登录会员服务要容易得多。这对你有用吗?

标签: asp.net-mvc asp.net-membership recurring-events


【解决方案1】:

PowerShell 对您来说可能是一个不错的选择。下面的示例演示了如何将表单值发布到登录页面,然后使用响应 cookie 对管理页面进行第二次调用。

注意,我从this post 借来了这个样本的大部分内容。

$LogonUrl = "http://yoursite.com/Account/LogOn"
$UserName = "AdminUser"
$Password = "pass@word1"
$AdminUrl = "http://yoursite.com/MyController/RunCleanupScript"

$cookies = New-Object System.Net.CookieContainer
$formData = "UserName=" + $UserName + "&Password=" + $Password

[net.httpWebRequest] $web1 = [net.webRequest]::create($LogonUrl)
$web1.method = "POST"
$web1.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
$web1.Headers.Add("Accept-Language: en-US")
$web1.Headers.Add("Accept-Encoding: gzip,deflate")
$web1.Headers.Add("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7")
$web1.AllowAutoRedirect = $false
$web1.ContentType = "application/x-www-form-urlencoded"
$buffer = [text.encoding]::ascii.getbytes($formData)
$web1.ContentLength = $buffer.length
$web1.TimeOut = 50000
$web1.KeepAlive = $true
$web1.Headers.Add("Keep-Alive: 300");
$web1.CookieContainer = $CookieContainer

$reqStrm = $web1.getRequestStream()
$reqStrm.write($buffer, 0, $buffer.length)
$reqStrm.flush()
$reqStrm.close()
[net.httpWebResponse] $response = $web1.getResponse()

$respStrm = $response.getResponseStream()
$reader = new-object IO.StreamReader($respStrm)
$result = $reader.ReadToEnd()
$response.close()

$web2 = new-object net.webclient
$web2.Headers.add("Cookie", $response.Headers["Set-Cookie"])
$result = $web2.DownloadString("$AdminUrl")

Write-Output $result

这也可以很容易地变成一个 Windows 控制台应用程序。无论哪种方式,它们都可以通过任务计划程序轻松安排。

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    表单身份验证以及调用网页以获取 cookie 的一些脚本可能不是满足您要求的最稳定和可维护的方法。

    您可以支持基本身份验证,这使得从脚本传递用户名和密码变得容易。有关如何在 asp.net mvc 中实现基本身份验证的示例,请参阅this blog post

    【讨论】:

      【解决方案3】:

      您可以编写一个控制台应用程序,它将执行 2 个 HTTP 请求:第一个是登录,第二个是获取受保护的资源:

      using System;
      using System.Collections.Specialized;
      using System.Net;
      
      public class WebClientEx: WebClient
      {
          private readonly CookieContainer _cookieContainer = new CookieContainer();
      
          protected override WebRequest GetWebRequest(Uri address)
          {
              var request = base.GetWebRequest(address);
              ((HttpWebRequest)request).CookieContainer = _cookieContainer;
              return request;
          }
      }
      
      class Program
      {
          static void Main()
          {
              using (var client = new WebClientEx())
              {
                  var values = new NameValueCollection
                  {
                      { "username", "user" },
                      { "password", "pwd" },
                  };
                  // Login
                  client.UploadValues("http://example.com/account/logon", values);
      
                  // Fetch the protected resource
                  var result = client.DownloadString("http://example.com/home/foo");
                  Console.WriteLine(result);
              }
          }
      }
      

      【讨论】:

      • WebClient cookie 感知可以很容易地在网站上按原样执行此操作。
      【解决方案4】:

      为什么不试试WatiNSelenium?您可以非常轻松地设置登录步骤,然后测试其他 RunCleanupScript 页面是否正常工作。

      WatiN 的主页示例:

      [Test] 
      public void SearchForWatiNOnGoogle()
      {
        using (var browser = new IE("http://www.google.com"))
        {
          browser.TextField(Find.ByName("q")).TypeText("WatiN");
          browser.Button(Find.ByName("btnG")).Click();
      
          Assert.IsTrue(browser.ContainsText("WatiN"));
        }
      }
      

      然后你可以有类似的东西:

      [Test] 
      public void TestRunCleanupScript()
      {
        using (var browser = new IE("www.mysite.com/MyController/RunCleanupScript"))
        {
          DoLogin(browser)
          //navigate to cleanupscript page      
          //your assert
        }
      }
      
      public void DoLogin(browser)
      {
        //navigate to login
        //type username and password and hit button
      }
      

      【讨论】:

        【解决方案5】:

        Phil Haak has a post关于可能对您有用的解决方案 - 他还警告相关的危险。您可以使用此方法来安排清理任务。如果您将清理代码移出控制器,则无需登录 - 永远不能在外部调用它。如果您仍然需要能够登录并强制清理,那么将清理代码移出控制器仍然是可行的方法。您的安全操作和调度程序代码都将调用清理代码。

        另一种选择可能是创建一个 Windows 服务,该服务会触发操作并将所需的凭据存储在其配置文件中。

        【讨论】:

          【解决方案6】:

          此代码将登录到 FormsAuthentication 站点,然后使用 AUTH cookie 访问站点上的任何其他 URL...

          string appURL = "https://.../LogOn";
          
          // UserName and Password should match the names of the inputs on your form
          string strPostData = String.Format("UserName={0}&Password={1}", "login", "pass");
          
          Cookie authCookie;
          CookieContainer cookieJar = new CookieContainer();
          
          // Prepare post to the login form
          HttpWebRequest req = (HttpWebRequest)WebRequest.Create(appURL);
          
          req.Method = "POST";
          req.ContentLength = strPostData.Length;
          req.ContentType = "application/x-www-form-urlencoded";
          req.CookieContainer = cookieJar;
          req.AutomaticDecompression = DecompressionMethods.GZip
                                       | DecompressionMethods.Deflate;
          
          // Proxy - Optional
          // req.Proxy.Credentials = CredentialCache.DefaultCredentials;
          
          // Post to the login form.
          StreamWriter swRequestWriter = new StreamWriter(req.GetRequestStream());
          swRequestWriter.Write(strPostData);
          swRequestWriter.Close();
          
          // Get the response.
          HttpWebResponse hwrWebResponse = (HttpWebResponse)req.GetResponse();
          
          
          // Store the required AUTH cookie
          authCookie = cookieJar.GetCookies(new Uri("... your cookie uri ..."))[".ASPXAUTH"];
          

          现在您可以使用 AUTH cookie 访问网站的任何其他 URL。

          HttpWebRequest req = (HttpWebRequest)WebRequest.Create("... url ...");
          
          req.CookieContainer.Add(new System.Net.Cookie(authCookie.Name,
                                    authCookie.Value,
                                    authCookie.Path, "localhost"));
          
          HttpWebResponse resp = (HttpWebResponse) req.GetResponse();
          

          【讨论】:

            【解决方案7】:

            我目前正在生产环境中执行此操作。就我而言,这个解决方案是显而易见的,因为已经安装了 MADAM,以便普通的 RSS 阅读器可以安全地访问网站上的 RSS 提要。

            这样做的诀窍是为您想要使用任何外部进程自动调用的页面启用基本身份验证,这为您提供了多种自动访问网站的方法;这个 VBScript 文件,例如调用维护 URL 并检查来自服务器的响应是否正是 SUCCESS

            Option Explicit
            
            Dim result
            result = PerformMaintenance("http://www.mysite.com/MyController/RunCleanupScript")
            WScript.Quit(result)
            
            Function PerformMaintenance(URL)
            
              Dim objRequest
            
              Set objRequest = CreateObject("Microsoft.XmlHttp")
            
              'I use a POST request because strictly speaking a GET shouldn't change anything on the server.
              objRequest.open "POST", URL, false, "LimitedDaemonUser", "SecretDaemonPassword"
              objRequest.Send
            
              if (objRequest.ResponseText = "SUCCESS") Then
                PerformMaintenance = 0
              Else
                PerformMaintenance = 1
              End If
            
              set objRequest = Nothing
            
            End Function
            

            基本身份验证很容易上手。只需将MADAM 包含在您的项目中,然后在您的Web.config 中进行配置。

            如果您使用标准 MembershipProvider,添加这些 Web.config 部分/参数 (IIS6) 应该可以使您的示例请求正常工作。您只需将MyNamespace.MembershipUserSecurityAuthority 更改为对实际类的引用。 MembershipUserSecurityAuthority 的源代码包含在 MADAM 中,位于演示 Web 应用程序的 App_Code 文件夹中。

            <configuration>
            <configSections>
                <sectionGroup name="madam">
                  <section name="userSecurityAuthority" type="System.Configuration.SingleTagSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
                  <section name="formsAuthenticationDisposition" type="Madam.FormsAuthenticationDispositionSectionHandler, Madam" />
                </sectionGroup>
            </configSections>
              <madam>
                <userSecurityAuthority realm="MyRealm" provider="MyNamespace.MembershipUserSecurityAuthority, MyNamespace" />
                <formsAuthenticationDisposition>
                  <discriminators all="false">
                    <discriminator inputExpression="Request.AppRelativeCurrentExecutionFilePath" pattern="~/MyController/RunCleanupScript$" type="Madam.RegexDiscriminator, Madam" />
                    </discriminators>
                </formsAuthenticationDisposition>
              </madam>
              <system.web>
                <httpModules>
                  <add name="FormsAuthenticationDisposition" type="Madam.FormsAuthenticationDispositionModule, Madam" />
                  <add name="AuthenticationModule" type="Madam.BasicAuthenticationModule, Madam" />
                </httpModules>
              </system.web>
            </configuration>
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-11-29
              • 1970-01-01
              • 1970-01-01
              • 2018-09-03
              • 1970-01-01
              • 1970-01-01
              • 2013-03-02
              • 2012-09-21
              相关资源
              最近更新 更多