asp.net-mvc ASP.NET MVC - HTTP 身份验证提示
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1606991/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC - HTTP Authentication Prompt
提问by zanona
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:
是否可以让我的应用程序在呈现视图之前询问用户名和密码提示?就像在 twitter API 上获取有关您帐户的信息一样:
http://twitter.com/account/verify_credentials.xml
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 请求基于 username:password 以及如下所示:
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:
当我尝试按照相同的结构构建 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
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.
我不认为 [Authorize] 过滤器是相同的,因为我相信它只是一个重定向,它将您重定向到基于帐户数据库的帐户内部控制器,在这种情况下,我将使用另一个数据库,特别是来自webservice并在提交信息后进行验证。但我需要采取行动来要求用户并根据其请求传递凭据。
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
实际上要请求需要此身份验证的页面(即 Twitter),我必须在其请求中声明这一点
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 provideinformation to the authentication prompt on request, how could I requirethis authentication on the request instead?
所以,这是完全相同的事情,但从另一方面来说,如果可以根据请求向身份验证提示提供信息,我怎么能要求对请求进行身份验证呢?
So everytime somebody tries to make a request to my application on example:
因此,每次有人尝试向我的应用程序发出请求时,例如:
http://myapplication/clients/verify_credentials
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 上的信息,例如它会是这样的
curl -u user:password http://myapplication/clients/verify_credentials
回答by ?a?da? Tekin
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).
好吧,要要求基本身份验证,您需要返回 401 状态代码。但是这样做会导致当前的身份验证模块执行其默认的未授权处理程序(对于表单身份验证,这意味着重定向到登录页面)。
I wrote an ActionFilterAttribteto see if I can get the behaviour you want when there's no authentication module installed in web.config.
我写了一个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();
}
}
}
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?
该操作成功打印了我输入的用户名和密码。但我真的怀疑这是做到这一点的最佳方式。除了这样要求用户名和密码,你别无选择吗?
回答by Darkseal
I modified the ?a?da? answer to put the whole logic inside my custom ActionFilter attribute.
我修改了?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();
}
}
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:
或特定的 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.
注意:上述实现需要开发人员手动插入用户名和密码作为 ActionFilter 所需的参数,但可以轻松扩展以使其支持任何授权机制(MembershipProvider、ASP.NET Identity、外部 DBMS 或文件上的自定义用户群等。 ) 通过删除自定义构造函数并相应地修改 OnActionExecuting 方法 IF 块。
For additional info, you can also read this postI wrote on my blog.
有关其他信息,您还可以阅读我在博客上写的这篇文章。
回答by Dale Ragan
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.
根据我所阅读的内容,您确实想创建一个服务而不是一个 Web 应用程序。我在这里猜测,但我认为您选择了 ASP.NET MVC 来利用路由并按照您想要的方式构建 URL?如果我错了,请纠正我。
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 articleshould help you get started if you want to go this route.
在我看来,如果您要返回数据,解决您遇到的问题的最佳方法是使用 WCF 构建 RESTful Web 服务。如果您想走这条路,这篇文章应该可以帮助您入门。
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.
否则,您将需要进一步向上堆栈以处理请求并对其进行身份验证。如果是这种情况,我可以帮助提供更多信息和代码。
回答by Will Bellman
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...
这是对我有用的方法。这是一个小动作,但它会使 IIS 和 MVC3 的行为更像所有其他基本 Http 身份验证系统,例如 Apache ...
Step 1.
第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.
确保为 IIS 安装了“基本身份验证”。
(例如:控制面板 -> 程序和功能 -> 打开或关闭 Windows 功能)
*我目前使用的是 Windows 7,但不确定确切路径。[GOOGLE:在 IIS 中安装基本身份验证] 应该会让你接近。
Step 2.
第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.
确保在您的站点下启用了基本身份验证。如果您必须在上一步安装它,您需要确保重置 IIS 服务并且所有应用程序池实际上都关闭了。
Step 3.
第 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:
(注意:我使用的是 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;
}
}
Step 3a. [edit]
步骤 3a。[编辑]
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.
将以下内容添加到您的 Web 配置中。请注意,我包括了周围的结构,例如“配置”标签……这只是一个路线图,如果您已经有了“配置”标签,请不要添加其他标签,否则 IIS 会惹恼您。
<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.
请注意,{Namespace}.ServiceModule 中的命名空间是您将第 3 步中的类放入的命名空间。
...and that's pretty much it.
……差不多就是这样。

