web-dev-qa-db-ja.com

ClaimsIdentity IsAuthenticatedが常にfalseになるのはなぜですか(Web API許可フィルターの場合)?

Web APIプロジェクトでは、通常の認証プロセスをオーバーライドして、代わりにトークンをチェックしています。コードは次のようになります。

if ( true ) // validate the token or whatever here
{
    var claims = new List<Claim>();
    claims.Add( new Claim( ClaimTypes.Name, "MyUser" ) );
    claims.Add( new Claim( ClaimTypes.NameIdentifier, "MyUserID" ) );
    claims.Add( new Claim( ClaimTypes.Role, "MyRole" ) );

    var claimsIdentity = new ClaimsIdentity( claims );

    var principal = new ClaimsPrincipal( new[] { claimsIdentity } );
    Thread.CurrentPrincipal = principal;
    HttpContext.Current.User = principal;
}

その後、[Authorize]属性をコントローラーに適用すると、承認に失敗します。

デバッグコードは同じ動作を確認します。

// ALWAYS FALSE!
if ( HttpContext.Current.User.Identity.IsAuthenticated ) {
    // do something
}

有効なClaimsIdentityを構築してスレッドに割り当てたにもかかわらず、ユーザーが認証されていないと考えるのはなぜですか?

64
explunit

問題は、.Net 4.5の重大な変更によるものです。 この記事 で説明したように、クレームIDを構築するだけではIsAuthenticatedがtrueを返すことはなくなりました。代わりに、コンストラクタに文字列(何でも構いません)を渡す必要があります。

上記のコードの次の行:

var claimsIdentity = new ClaimsIdentity( claims );

これになる:

// exact string doesn't matter
var claimsIdentity = new ClaimsIdentity( claims, "CustomApiKeyAuth" );

そして問題は解決されました。 更新:Leoからの他の回答を参照してください。正確なAuthenticationType値は、認証パイプラインに他に何があるかによって重要になる場合とそうでない場合があります。

アップデート2:コメントでロビン・ファン・デル・クナップが示唆したように、System.Security.Claims.AuthenticationTypes値が適切な場合があります。

var claimsIdentity = new ClaimsIdentity( claims, AuthenticationTypes.Password );

// and elsewhere in your application...
if (User.Identity.AuthenticationType == AuthenticationTypes.Password) {
    // ...
}
120
explunit

提供された回答にはある程度の妥当性がありますが、完全に正しいわけではありません。文字列を追加するだけで魔法のように機能するとは限りません。コメントの1つで述べたように、この文字列は AuthenticationTypes 列挙の1つと一致する必要があり、これはOWIN認証/承認ミドルウェアで指定されたものと一致する必要があります。 ...

public void ConfigureOAuth(IAppBuilder app)
        {
            app.UseCors(CorsOptions.AllowAll);

            OAuthAuthorizationServerOptions serverOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new Microsoft.Owin.PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                AuthenticationType = AuthenticationTypes.Password,
                AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
                Provider = new AppAuthServerProvider()
            };


            app.UseOAuthAuthorizationServer(serverOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
                {
                    AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
                    AuthenticationType = AuthenticationTypes.Password
                });            
        }

ただし、上記のシナリオではそれほど重要ではありません。ただし、より多くの認証/承認レベルを使用している場合、同じAuthenticationType...に一致するものにクレームが関連付けられます...別の例は、Cookie認証を使用する場合です...

public void Configuration(IAppBuilder app)
        {
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "ApplicationCookie",
                LoginPath = new PathString("/auth/login")
            });
        }

ここで、AuthenticationTypeはCookieの名前を表します。アプリは他のプロバイダーから他のCookieを取得している可能性があるため、正しいインスタンスに関連付けるには、クレームをインスタンス化するときにAuthenticationTypeを設定することが重要ですクッキー

11
Leo