27

是否可以让我的应用程序在呈现视图之前要求用户名和密码提示?就像在 twitter API 上获取有关您帐户的信息一样:

http://twitter.com/account/verify_credentials.xml

所以在渲染视图之前|| 它要求您插入用户名和密码的文件,我认为这是直接在服务器上进行的,因为 curl 请求基于用户名:密码,如下所示:

curl -u user:password http://twitter.com/account/verify_credentials.xml

当我尝试按照相同的结构构建 API 时,我想知道如何在 ASP.NET MVC C# 上做到这一点。我已经在 ruby​​ rails 上使用过它,它非常简单,例如:

before_filter :authenticate

def authenticate
    authenticate_or_request_with_http_basic do |username, password|
    username == "foo" && password == "bar"
end

我不认为 [Authorize] 过滤器是相同的,因为我相信它只是一个重定向,它会将您重定向到基于帐户数据库的帐户内部控制器,在这种情况下,我将使用另一个数据库,特别是来自webservice 并在提交信息后进行验证。但我需要采取行动来要求用户并根据其请求传递凭据。

提前致谢


更新:

实际上,要请求需要此身份验证的页面(即 Twitter),我必须在其请求中声明这一点

request.Credentials = new NetworkCredential("username", "password");

这将反映提示的用户名和密码。

所以,这完全一样,但从另一方面来说,如果可以根据请求向身份验证提示提供信息,我怎么能要求对请求进行此身份验证呢?

因此,每次有人尝试向我的应用程序发出请求时:

http://myapplication/clients/verify_credentials

它应该使用该服务器提示询问用户名和密码,以便检索有关 curl 的信息,例如它会是这样的

curl -u user:password http://myapplication/clients/verify_credentials
4

4 回答 4

48

好吧,要要求基本身份验证,您需要返回 401 状态代码。但是这样做会导致当前的身份验证模块执行其默认的未经授权的处理程序(对于表单身份验证,这意味着重定向到登录页面)。

我写了一个ActionFilterAttribte看看我是否可以在没有安装身份验证模块的情况下获得你想要的行为web.config

public class RequireBasicAuthentication : ActionFilterAttribute {
   public override void OnActionExecuting(ActionExecutingContext filterContext) {
       var req = filterContext.HttpContext.Request;
       if (String.IsNullOrEmpty(req.Headers["Authorization"])) {
           var res = filterContext.HttpContext.Response;
           res.StatusCode = 401;
           res.AddHeader("WWW-Authenticate", "Basic realm=\"Twitter\"");
           res.End();
       }
   }
}

和控制器动作:

[RequireBasicAuthentication]
public ActionResult Index() {
    var cred = System.Text.ASCIIEncoding.ASCII
            .GetString(Convert.FromBase64String(
            Request.Headers["Authorization"].Substring(6)))
            .Split(':');
    var user = new { Name = cred[0], Pass = cred[1] };
    return Content(String.Format("user:{0}, password:{1}", 
        user.Name, user.Pass));
}

该操作成功打印了我输入的用户名和密码。但我真的怀疑这是最好的方法。除了以这种方式询问用户名和密码之外,您别无选择?

于 2009-10-22T14:17:14.090 回答
3

根据我所阅读的内容,您真的想创建服务而不是 Web 应用程序。我在这里猜测,但我认为您选择了 ASP.NET MVC 来利用路由并以您想要的方式构建 URL?如果我错了,请纠正我。

在我看来,解决您遇到的问题的最佳方法是在返回数据时使用 WCF 构建 RESTful Web 服务。如果您想走这条路,这篇文章应该可以帮助您入门。

否则,您将需要更进一步地处理请求并对其进行身份验证。如果是这种情况,我可以帮助提供更多信息和代码。

于 2009-10-22T15:28:19.110 回答
3

我修改了 çağdaş 答案,将整个逻辑放在我的自定义 ActionFilter 属性中。

public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    public string BasicRealm { get; set; }
    protected string Username { get; set; }
    protected string Password { get; set; }

    public BasicAuthenticationAttribute(string username, string password)
    {
        this.Username = username;
        this.Password = password;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"];
        if (!String.IsNullOrEmpty(auth))
        {
            var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
            var user = new { Name = cred[0], Pass = cred[1] };
            if (user.Name == Username && user.Pass == Password) return;
        }
        var res = filterContext.HttpContext.Response;
        res.StatusCode = 401;
        res.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Ryadel"));
        res.End();
    }
}

它可用于将整个控制器置于基本身份验证之下:

[BasicAuthenticationAttribute("your-username", "your-password", 
    BasicRealm = "your-realm")]
public class HomeController : BaseController
{
   ...
}

或特定的 ActionResult:

public class HomeController : BaseController
{
    [BasicAuthenticationAttribute("your-username", "your-password", 
        BasicRealm = "your-realm")]
    public ActionResult Index() 
    {
        ...
    }
}

注意:上述实现需要开发人员手动插入用户名和密码作为 ActionFilter 所需的参数,但可以轻松扩展以使其支持任何授权机制(MembershipProvider、ASP.NET Identity、外部 DBMS 或文件上的自定义用户库等)。 ) 通过删除自定义构造函数并相应地修改 OnActionExecuting 方法 IF 块。

有关更多信息,您还可以阅读我在博客上写的这篇文章。

于 2014-12-07T23:04:22.437 回答
2

这是对我有用的方法。这是一个小动作,但它会使 IIS 和 MVC3 的行为更像所有其他基本 Http 身份验证系统,如 Apache ......

步骤1。

确保为 IIS 安装了“基本身份验证”。

(示例:控制面板 -> 程序和功能 -> 打开或关闭 Windows 功能)

*我目前使用的是 Windows 7,不确定确切的路径。[GOOGLE:在 IIS 中安装基本身份验证] 应该让你接近。

第2步。

确保在您的站点下启用了基本身份验证。如果您必须在上一步中安装它,您需要确保重置 IIS 服务并且所有应用程序池实际上都已关闭。

步骤 3。

(注意:我使用的是 MVC3,并且觉得这应该适用于大多数模型,包括 ASP.Net,而不用大惊小怪。)
在您的项目中,您需要添加以下类:

public class ServicePrincipal : IPrincipal { // This answers the "What am I allowed to do" question

  // In real life, this guy will contain all your user info
  // and you can put what ever you like and retrieve it 
  // later via the HttpContext, on your application side.
  // Some fun with casting will be required.

  public static IPrincipal Default { 
    get {
      return new ServicePrincipal {
        Identity = new ServiceIdentity {
          AuthenticationType = "Test",
          IsAuthenticated = true,
          Name = "Basic"
        }
      };
    }
  }

  public IIdentity Identity { get; set; } 

  public bool IsInRole(string role) {
    // If you want to use role based authorization
    // e.g. [Authorize(Roles = "CoolPeople")]
    // This is the place to do it and you can do
    // anything from load info from a db or flat file
    // or simple case statement...though that would 
    // be silly.
    return true;
  }
}

public class ServiceIdentity : IIdentity { // This answers the "Who Am I" Question
  public string AuthenticationType { get; set; }

  public bool IsAuthenticated { get; set; }

  public string Name { get; set; }
}


public class ServiceModule : IHttpModule { // This is the module for IIS
  public void Init(HttpApplication context) {
    context.AuthenticateRequest += this.BasicAuthenticationRequest;
  }

  public void BasicAuthenticationRequest(object sender, EventArgs e) {
    HttpApplication app = sender as HttpApplication;

    if( !ServiceProvider.Authenticate(app.Context) ) {
      // Total FAIL!
    }
  }

  public void Dispose() {
    // Clean up the mess, if needed.
  }

}

public class ServiceProvider {

  public static bool Authenticate( HttpContext context ) {
    // For the example we are going to create a nothing user
    // say he is awesome, pass him along through and be done.
    // The heavy lifting of the auth process will go here 
    // in the real world.

    HttpContext.Current.User = ServicePrincipal.Default;
    return true;
  }  
}

步骤 3a。[编辑]

这是您将“使用”的不同库

using System.Security.Principal;
using System.Web;

只是想把它们扔进去。我讨厌人们把它们放在外面。:)

第4步。

将以下内容添加到您的 Web 配置中。请注意我包括了周围的结构,例如“配置”标签......这只是一个路线图,如果您已经有一个“配置”标签,请不要添加其他标签,否则 IIS 会惹怒您。

<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ServiceCredentialModule" type="{Namespace}.ServiceModule"/>
    </modules>
  </system.webServer>
<configuration>

请注意,{Namespace}.ServiceModule 中的命名空间是您将第 3 步中的类放入的命名空间。

……差不多就是这样。

于 2012-04-09T19:30:21.950 回答