3

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

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

  1. 登录
  2. 呼叫网址

所以可以说网址是

www.mysite.com/MyController/RunCleanupScript

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

4

7 回答 7

4

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

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

于 2011-10-21T12:03:17.703 回答
2

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

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

于 2011-10-20T05:44:24.707 回答
2

您可以编写一个控制台应用程序,它将执行 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);
        }
    }
}
于 2011-10-20T06:02:12.427 回答
1

此代码将登录到 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();
于 2011-10-22T07:18:03.580 回答
0

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

请注意,我从这篇文章中借用了大部分示例。

$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 控制台应用程序。无论哪种方式,它们都可以使用任务计划程序轻松安排。

希望这可以帮助。

于 2011-10-20T00:23:13.603 回答
0

为什么不试试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
}
于 2011-10-20T10:31:21.147 回答
0

我目前正在生产环境中执行此操作。在我的例子中,这个解决方案是显而易见的,因为已经安装了 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为对实际类的引用。MADAM的源代码MembershipUserSecurityAuthority包含在演示 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>
于 2011-10-23T20:12:43.997 回答