web-dev-qa-db-ja.com

ASP.NETMVC-HTTP認証プロンプト

ビューをレンダリングする前に、アプリケーションにユーザー名とパスワードの入力を求めるようにさせることはできますか? Twitter APIの場合と同様に、アカウントに関する情報を取得します。

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

したがって、ビューをレンダリングする前に||ファイルでは、ユーザー名とパスワードの挿入を求められます。curlリクエストはusername:passwordに基づいているため、これはサーバー上で直接行われると思います。

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

[承認]フィルターは単なるリダイレクトであると信じているため、同じではないと思います。これにより、アカウントデータベースに基づくアカウント内部コントローラーにリダイレクトされます。この場合は、別のデータベースを使用します。情報が送信された後、Webサービスと検証を行います。しかし、ユーザーを要求し、その要求に応じて資格情報を渡すアクションが必要です。

前もって感謝します


更新:

実際にこの認証を必要とするページ(Twitterなど)をリクエストするには、リクエスト時にこれを宣言する必要があります

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

そして、これはそのプロンプトされたユーザー名とパスワードを反映します。

ですから、それはまったく同じことですが、可能であれば反対側からです 提供する リクエストに応じて認証プロンプトへの情報、どうすればよいですか? 必要とする 代わりに、リクエストに対するこの認証?

したがって、誰かが私のアプリケーションにリクエストを送信しようとするたびに、次のようになります。

http:// myapplication /クライアント/ verify_credentials

そのサーバーでユーザー名とパスワードを要求する必要がありますプロンプトを表示して、curlに関する情報を取得します。たとえば、次のようになります。

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

基本認証を要求するには、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));
}

このアクションにより、入力したユーザー名とパスワードが正常に出力されます。しかし、私はそれがこれを行うための最良の方法であるとは本当に疑っています。この方法でユーザー名とパスワードを要求する以外に選択肢はありませんか?

47
Çağdaş Tekin

私が読んだ内容に基づいて、Webアプリケーションではなく、サービスを作成したいと考えています。ここで推測していますが、ルーティングを利用してURLを希望どおりに構築するためにASP.NET MVCを選択したと思いますか?私が間違っている場合は私を訂正してください。

私の意見では、あなたが抱えている問題を解決する最良の方法は、データを返す場合にWCFを使用してRESTfulWebサービスを構築することです。この 記事 は、このルートに行きたい場合に始めるのに役立つはずです。

それ以外の場合は、リクエストを処理して認証するために、スタックをさらに上に移動する必要があります。その場合は、より多くの情報とコードを提供するお手伝いをします。

3
Dale Ragan

ロジック全体をカスタムActionFilter属性内に配置するように、çağdaşの回答を変更しました。

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() 
    {
        ...
    }
}

[〜#〜] note [〜#〜]:上記の実装では、開発者はユーザー名とパスワードをActionFilterの必須パラメーターとして手動で挿入する必要がありますが、カスタムコンストラクターを削除し、それに応じてOnActionExecutingメソッドIFブロックを変更することで、任意の承認メカニズム(MembershipProvider、ASP.NET Identity、外部DBMSまたはファイルのカスタムユーザーベースなど)をサポートするように簡単に拡張できます。

追加情報については、次のこともできます この投稿を読んでください ブログに書きました。

3
Darkseal

これが私のために働いた方法です。少し手間がかかりますが、IISとMVC3は、Apacheなどの他のすべての基本Http認証システムと同じように動作します...

ステップ1。

IISに「基本認証」がインストールされていることを確認してください。

(例:[コントロールパネル]-> [プログラムと機能]-> [Windowsの機能をオンまたはオフにする])

*現在Windows7を使用していますが、正確なパスがわかりません。 [グーグル: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のクラスを配置する名前空間であることに注意してください。

...そしてそれはほとんどそれです。

2
Will Bellman