1

多くのブログ、MSDN ドキュメント、サンプル コード、およびその他のスタック オーバーフローに関する質問を読んで、しばらくの間これを理解しようとしてきましたが、まだこれを機能させていません。

これが私のシナリオです:

Windows Azure を使用して 2 つの Web ロールをホストしています。1 つは私の MVC4 Web API で、もう 1 つは Web API を使用する MVC4 Web アプリです。Web API にアクセスする .NET を使用する多数のクライアント アプリケーションもあります。

したがって、私の主なコンポーネントは次のとおりです。

  • Web API
  • ウェブアプリ
  • .NET クライアント

Web アプリで「ホスト」されているフォーム認証を使用したいと考えています。組み込みの simplemembership 認証メカニズムを使用していますが、うまく機能します。Web アプリでアカウントを作成してログインできます。

ここで、これらの同じアカウントを使用して、Web アプリと任意の .NET クライアント アプリの両方から Web API を認証したいと考えています。

私はこれを行うための多くの方法を読みましたが、Web API で基本認証を使用するのが最も簡単なようです。現在、正確な問題を解決しているように見えるため、このコードを使用しています:フォーム認証、基本認証、およびSimpleMembershipの混合

私はこれを機能させることができません。Web アプリ (127.0.0.1:81) に正常にログインし、認証 (127.0.0.1:8081/api/values など) を必要とする Web API を呼び出そうとすると、401 (未承認)応答で呼び出しが失敗します。 . コードをステップ実行すると、WebSecurity.IsAuthenticated は false を返します。WebSecurity.Initialized は true を返します。

このコードを実装し、次のコードを使用して (ログイン後に) Web アプリから Web API を呼び出そうとしています。

using ( var handler = new HttpClientHandler() )
{
    var cookie = FormsAuthentication.GetAuthCookie( User.Identity.Name, false );
    handler.CookieContainer.Add( new Cookie( cookie.Name, cookie.Value, cookie.Path, cookie.Domain ) );

    using ( var client = new HttpClient() )
    {
        //client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
        //  "Basic",
        //  Convert.ToBase64String( System.Text.ASCIIEncoding.ASCII.GetBytes(
        //  string.Format( "{0}:{1}", User.Identity.Name, "123456" ) ) ) );
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
            "Cookie",
            Convert.ToBase64String( System.Text.ASCIIEncoding.ASCII.GetBytes( User.Identity.Name ) ) );

        string response = await client.GetStringAsync( "http://127.0.0.1:8080/api/values" );

        ViewBag.Values = response;
    }
}

ご覧のとおり、Cookie とユーザー名/パスワードの両方を使用してみました。明らかに私はクッキーを使いたいのですが、この時点で何かがうまくいくなら、それは良いステップです!

Web API の ValuesController は適切に装飾されています。

// GET api/values
[BasicAuthorize]
public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

Web API の Global.asax.cs で、SimpleMembership を初期化しています。

// initialize our SimpleMembership connection
try
{
    WebSecurity.InitializeDatabaseConnection( "AzureConnection", "User", "Id", "Email", autoCreateTables: false );
}
catch ( Exception ex )
{
    throw new InvalidOperationException( "The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex );
}

これは成功し、WebSecurity は後で初期化されたと言うので、この部分はすべて正常に動作していると思います。

私の構成ファイルには、 MSDNごとに必要な認証設定が一致しています。

API構成は次のとおりです。

<authentication mode="Forms">
<forms protection="All" path="/" domain="127.0.0.1" enableCrossAppRedirects="true" timeout="2880" />
</authentication>
<machineKey decryption="AES" decryptionKey="***" validation="SHA1" validationKey="***" />

Web アプリの構成は次のとおりです。

<authentication mode="Forms">
<forms loginUrl="~/Account/Login" protection="All" path="/" domain="127.0.0.1" enableCrossAppRedirects="true" timeout="2880" />
</authentication>
<machineKey decryption="AES" decryptionKey="***" validation="SHA1" validationKey="***" />

これをローカルで試していることに注意してください (したがって 127.0.0.1 ドメイン) が、Azure でホストされているデータベースを参照しています。

Web ロール間で動作させることさえできないため、.NET クライアント アプリケーションからこれを試す必要はありません。クライアント アプリの場合、理想的には Web 呼び出しを行い、ユーザー名とパスワードを渡し、Cookie を取得し、さらに Web API 要求にその Cookie を使用します。

非常にシンプルに見え、私の要件を満たしているので、私が働いているものを手に入れたいと思います。

Thinktectureなどの他のソリューションは、必要以上に多くの機能があり、必要ではないように思われるため、まだ試していません。

私は何が欠けていますか?

4

1 に答える 1

1

まあ、これは恥ずかしいです。私の主な問題は、単純なコード エラーでした。これが正しいコードです。私の質問のコードとの違いを見つけることができると教えてください。

using ( var handler = new HttpClientHandler() )
{
    var cookie = FormsAuthentication.GetAuthCookie( User.Identity.Name, false );
    handler.CookieContainer.Add( new Cookie( cookie.Name, cookie.Value, cookie.Path, cookie.Domain ) );

    using ( var client = new HttpClient( handler ) )
...
}

403 Forbiddenそれが修正されると、エラーが発生し始めました。そこで私はそれを追跡し、ロールが指定されていない場合に属性BasicAuthorizeAttributeを適切にサポートするようにクラスに小さな変更を加えました。[BasicAuthorize]

変更されたコードは次のとおりです。

private bool isAuthorized( string username )
{
    // if there are no roles, we're good!
    if ( this.Roles == "" )
        return true;

    bool authorized = false;

    var roles = (SimpleRoleProvider)System.Web.Security.Roles.Provider;
    authorized = roles.IsUserInRole( username, this.Roles );
    return authorized;
}

その変更により、フォーム Cookie を渡すことによる基本認証が機能します。

ここで、非 Web クライアント アプリを動作させてから、Web アプリを推奨どおりにリファクタリングします。

これが将来誰かに役立つことを願っています!

于 2013-08-29T20:40:39.023 に答える