ASP.NET MVC - HTTP 身份验证提示

发布于 2024-08-09 01:11:37 字数 1406 浏览 8 评论 0原文

是否可以让我的应用程序在渲染视图之前要求输入用户名和密码? 就像在 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] 过滤器是相同的,因为我相信它只是一个重定向, 它会将您重定向到基于帐户数据库的帐户内部控制器,在这种情况下,我将使用另一个数据库,特别是来自网络服务的数据库,并在提交信息后进行验证。 但我需要采取行动来要求用户并根据其请求传递凭据。

提前感谢


更新:

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

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

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

因此,这是完全相同的事情,但从另一方面来看,如果可以根据请求向身份验证提示提供信息,我如何要求对请求进行此身份验证?

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

http://myapplication/clients/verify_credentials

它应该使用该服务器提示符询问用户名和密码 例如,要检索有关卷曲的信息,就会像这样

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

Is it possible to make my application ask for username and password prompting for it before render a view?
Just like on twitter API to get information about your account:

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

So before render the view || file it asks you to insert you username and password, I think this is made directly on the server since the curl request is based on username:password as well like this:

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

As I'm trying to build an API following the same structure I would like to know how I can do this on ASP.NET MVC C#. I've already used this on ruby rails and its pretty simple like:

before_filter :authenticate

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

I don't think that [Authorize] filter is the same since I believe it's just a redirection,
and it redirects you to the Accounts Internal Controller that is based on the accounts database, in this case I will use another database, specifically from a webservice and do the validation after the information is submitted.
But I need the action to require the user and pass credentials on its request.

Thanks in advance


UPDATE:

Actually to request a page that requires this authentication (i.e. Twitter)
I would have to declare this on its request

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

And this would reflect that prompted username and password.

So, it's exactly the same thing but from the other side, if it's possible to provide information to the authentication prompt on request, how could I require this authentication on the request instead?

So everytime somebody tries to make a request to my application on example:

http://myapplication/clients/verify_credentials

it should ask for a username and password with that server prompt
so to retrive information on curl for example it would be like this

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

你曾走过我的故事 2024-08-16 01:11:37

那么,要要求基本身份验证,您需要返回 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));
}

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

Well, to require basic authentication you need to return 401 status code. But doing that will cause the current authentication module to execute its default unauthorized handler (for forms authentication, this means redirecting to login page).

I wrote an ActionFilterAttribte to see if I can get the behaviour you want when there's no authentication module installed in 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();
       }
   }
}

And the controller action :

[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));
}

That action successfully prints the username and password I enter. But I really doubt that's the best way to do this. Do you have no choice except asking for username and password this way?

謸气贵蔟 2024-08-16 01:11:37

这是对我有用的方法。这是一个小工作,但它将使 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 步。

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

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

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

...差不多就是这样了。

Here's the way that has worked for me. It's a little foot work but it will make IIS and MVC3 behave a lot more like all the other Basic Http authentication systems, like Apache...

Step 1.

Make sure "Basic Authentication" is installed for IIS.

( Example: Control Panel -> Programs and Features -> Turn Windows features on or off )

*I'm using Windows 7 at the moment and am not sure the exact path. [GOOGLE: installing basic authentication in IIS] should get you close.

Step 2.

Make sure Basic Authentication is enabled under your site. If you had to install this in the previous step you need to make sure you reset the IIS service and that all the app pools actually went down.

Step 3.

(Note: I am using MVC3, and feel this should work in most models, including ASP.Net, without a lot of fuss.)
In your project you will need to add the following classes:

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;
  }  
}

Step 3a. [edit]

Here's the different libs you'll be "using"

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

Just wanted to throw those in. I hate it when folks leave them out. :)

Step 4.

Add the following to your web config. Please note I am including the surrounding structure, for example the "configuration" tag... It's just a road map, if you already have a "configuration" tag don't add the other or IIS gets upset with you.

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

Please note that the Namespace in {Namespace}.ServiceModule is the Namespace you put the classes from Step 3 into.

...and that's pretty much it.

昵称有卵用 2024-08-16 01:11:37

我修改了 ç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 所需的参数,但可以轻松扩展为通过删除自定义构造函数并相应地修改 OnActionExecuting 方法 IF 块,使其支持任何授权机制(MembershipProvider、ASP.NET Identity、外部 DBMS 或文件上的自定义用户库等)。

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

I modified the çağdaş answer to put the whole logic inside my custom ActionFilter attribute.

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();
    }
}

It can be used to put under Basic Authentication a whole controller:

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

or a specific ActionResult:

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

NOTE: The above implementation requires the developer to manually insert the username and password as ActionFilter required parameters but can be easily extended to make it support any authorization mechanism (MembershipProvider, ASP.NET Identity, custom userbase on an external DBMS or file, etc.) by removing the custom constructor and modifying the OnActionExecuting method IF block accordingly.

For additional info, you can also read this post I wrote on my blog.

游魂 2024-08-16 01:11:37

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

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

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

You really want to create a service and not a web application, based on what I have read. I am guessing here, but I think you picked ASP.NET MVC to take advantage of the routing and building the URL's the way you want? Correct me if I am wrong.

In my opinion the best way to solve the problem you are having is to build RESTful web services with WCF if you are returning data. This article should help you get started if you want to go this route.

Otherwise, you will need to go further up the stack for handling the request and authenticating it. If this is the case, I can help with providing more info and code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文