47

Web API を使用した ASP.NET MVC 4 プロジェクトがあります。コントローラーで、[Authorize] 属性を使用して承認を要求するようにクラスを設定しました。認証には、ASP.NET メンバーシップ プロバイダーを使用しており、Web.Config を「フォーム」認証を使用するように設定しています。これが私が立ち往生している場所です:

API のテストが完了するまで、すべてがうまく機能しており、コントローラーを [Authorize] 属性で保護して、メンバーシップ プロバイダーでユーザーに対する認証のテストを開始できるようにしたいと考えています。そこで、Fiddler を起動し、次のようにメンバーシップ プロバイダーからのユーザー名:パスワードと共に Authorization:Basic 属性を追加して同じ呼び出しを行います。

ここに画像の説明を入力

私が受け取る応答は 401 無許可で、「Auth」の下に「No WWW-Authenticate Header is present.」と表示されます。次に、API が SHA1 でエンコードされたキーを探していることに気付きました。そこで、検索から SHA1 ジェネレーターを起動し、username:password のハッシュを取得して、次のようにリクエスト ヘッダーを更新します。

ここに画像の説明を入力

これも機能せず、同じ結果が得られます。また、サーバーでユーザー名/パスワードをデコードするために、ある種の「共有秘密鍵」が必要であることは明らかです。

だから私の質問:

  1. このキーをサーバー (この場合は VS 2012 で実行されている仮想 IIS) から取得するにはどうすればよいですか。
  2. これを使用して、ASP.NET メンバーシップ プロバイダーからのユーザー名/パスワードを使用して Fiddler で認証された呼び出しを行うにはどうすればよいですか。
  3. クライアント アプリケーションでこれを使用して同じ呼び出しを行う方法 (C# WPF アプリ)。
  4. HTTP 呼び出しで SSL と組み合わせた場合、これは最善の方法ですか? そうでない場合は何ですか?

前もって感謝します!

4

1 に答える 1

71

SSL で基本認証を使用できます。サーバー側では、登録したメンバーシップ プロバイダーにクエリを実行して資格情報を検証し、有効な場合はロールを取得して現在のプリンシパルを設定するカスタム委任ハンドラーを作成できます。

public class BasicAuthenticationMessageHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var authHeader = request.Headers.Authorization;

        if (authHeader == null)
        {
            return base.SendAsync(request, cancellationToken);
        }

        if (authHeader.Scheme != "Basic")
        {
            return base.SendAsync(request, cancellationToken);
        }

        var encodedUserPass = authHeader.Parameter.Trim();
        var userPass = Encoding.ASCII.GetString(Convert.FromBase64String(encodedUserPass));
        var parts = userPass.Split(":".ToCharArray());
        var username = parts[0];
        var password = parts[1];

        if (!Membership.ValidateUser(username, password))
        {
            return base.SendAsync(request, cancellationToken);
        }

        var identity = new GenericIdentity(username, "Basic");
        string[] roles = Roles.Provider.GetRolesForUser(username);
        var principal = new GenericPrincipal(identity, roles);
        Thread.CurrentPrincipal = principal;
        if (HttpContext.Current != null)
        {
            HttpContext.Current.User = principal;
        }

        return base.SendAsync(request, cancellationToken);
    }
}

次に、このハンドラーを に登録しApplication_Startます。

GlobalConfiguration.Configuration.MessageHandlers.Add(
    new BasicAuthenticationMessageHandler()
);

[Authorize] 属性で装飾された Api コントローラーを使用して、認証されたユーザーのみがそのアクションにアクセスできるようにすることができます。

[Authorize]
public class ValuesController : ApiController
{
    public string Get()
    {
        return string.Format("Hello {0}", User.Identity.Name);
    }
}

それでは、サンプル クライアントを見てみましょう。

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

class Program
{
    static void Main()
    {
        // since for testing purposes I am using IIS Express
        // with an invalid SSL certificate I need to desactivate
        // the check for this certificate.
        ServicePointManager.ServerCertificateValidationCallback += 
            (sender, certificate, chain, sslPolicyErrors) => true;

        using (var client = new HttpClient())
        {
            var buffer = Encoding.ASCII.GetBytes("john:secret");
            var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(buffer));
            client.DefaultRequestHeaders.Authorization = authHeader;
            var task = client.GetAsync("https://localhost:44300/api/values");
            if (task.Result.StatusCode == HttpStatusCode.Unauthorized)
            {
                Console.WriteLine("wrong credentials");
            }
            else
            {
                task.Result.EnsureSuccessStatusCode();
                Console.WriteLine(task.Result.Content.ReadAsAsync<string>().Result);
            }
        }
    }
}
于 2012-07-18T07:29:47.270 に答える