User.Identity.IsAuthenticated は同一リクエスト中ではサインアウトしても更新されない

はまりかけたのでメモ。環境は以下の通りです。

.NET の認証機構を使用している場合、ユーザーが認証済みかどうかは以下の様なコードでチェックできます。

            if (HttpContext.User.Identity.IsAuthenticated)
            {
                // 認証済みである
            }

ところが、サインアウト処理を行っても、同一リクエスト内では上記の値は更新されません。例えば ASP.NET Identity を使っている場合、以下の様な動きになります。

            // サインアウト処理
            var authentication = HttpContext.GetOwinContext().Authentication;
            authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

            if (HttpContext.User.Identity.IsAuthenticated)
            {
                // ここに入る!
            }

普通はサインアウト処理の後にリダイレクトすることが多いので、リダイレクト後には結果が false になるので問題にならないのですが、なんか特殊なチェック処理の結果、強制的にログアウト処理を行いたいような場合に困ります。

結論としては、 HttpContext.User (実体は IPrincipal )を上書きしてしまえばいいようです。

先ほどのコードは以下のようにします。

            var authentication = HttpContext.GetOwinContext().Authentication;
            authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

            // User を上書き
            HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);

            if (HttpContext.User.Identity.IsAuthenticated)
            {
                // ここに入らなくなった!
            }

User に渡すインスタンスはこれでいいのか?というあたりが不安な感じですが、とりあえずは意図したとおりに動きました。なお、デバッガで確認してみると、サインイン前には User に System.Security.Principal.WindowsPrincipalインスタンスが入ってくるようです。

まぁ、もしリダイレクトしてもよいのであればそうするのが無難かと思います。