1. ホーム
  2. asp.net

[解決済み] ASP.NET_SessionId + OWIN Cookieがブラウザに送信されない。

2022-05-10 06:20:45

質問

OwinのCookie認証を使用する際に、奇妙な問題が発生しました。

IISサーバーを起動すると、IE/FirefoxとChromeで認証が完全にうまくいきます。

私は、認証と異なるプラットフォームでのログインについていくつかのテストを行い始め、奇妙なエラーに行き当たりました。散発的に、Owin フレームワーク/IIS は、ブラウザーに Cookie を送信しないのです。ユーザー名とパスワードを入力すると、コードは正しく実行されますが、クッキーはブラウザにまったく送信されません。サーバーを再起動すると動き始め、ある時点でログインしようとすると、またクッキーが配信されなくなります。コードを踏み越えることは何もしませんし、エラーも投げません。

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            CookieHttpOnly = true,
            AuthenticationType = "ABC",
            LoginPath = new PathString("/Account/Login"),
            CookiePath = "/",
            CookieName = "ABC",
            Provider = new CookieAuthenticationProvider
               {
                  OnApplyRedirect = ctx =>
                  {
                     if (!IsAjaxRequest(ctx.Request))
                     {
                        ctx.Response.Redirect(ctx.RedirectUri);
                     }
                 }
               }
        });

そして、ログインプロシージャーの中に、以下のようなコードがあります。

IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
                            authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

var authentication = HttpContext.Current.GetOwinContext().Authentication;
var identity = new ClaimsIdentity("ABC");
identity.AddClaim(new Claim(ClaimTypes.Name, user.Username));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.User_ID.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Role, role.myRole.ToString()));
    authentication.AuthenticationResponseGrant =
        new AuthenticationResponseGrant(identity, new AuthenticationProperties()
                                                   {
                                                       IsPersistent = isPersistent
                                                   });

authenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, identity);

更新1です。 この問題の原因の一つは、セッションに項目を追加したときに問題が発生することだと思われます。単純なものを追加する Session.Content["ABC"]= 123 のような単純なものを追加すると、問題が発生するようです。

私が確認できることは、以下の通りです。 1) (Chrome)ログインすると、ASP.NET_SessionId + 認証Cookieを取得します。 2) 私はsession.contentsを設定するページに行く... 3) 新しいブラウザ(Firefox)を開いてログインしてみると、ASP.NET_SessionIdも認証クッキーも受け取れません。 4) 最初のブラウザがASP.NET_SessionIdを持っている間、それは動作し続けます。このクッキーを削除すると、他のすべてのブラウザと同じ問題が発生します。 私は、IPアドレス(10.x.x.x)とlocalhostで作業しています。

更新 2。 強制的に ASPNET_SessionId を強制的に作成します。

1) OWINで認証する前に、私はランダムな Session.Content の値をログインページで作成し、ASP.NET_SessionIdを開始します。 2) その後、私は認証し、さらにセッションを作成します。 3) 他のブラウザでも動作するようです。

これは奇妙なことです。これは、ASP と OWIN が異なるドメインにあると考えるか、そのようなことと関係があると結論付けるしかありません。

アップデート 3 - の間で奇妙な動作をしています。

追加の奇妙な挙動を確認 - Owin と ASP セッションのタイムアウトが異なる。私が見ているのは、私のOwinセッションが、何らかのメカニズムによってASPセッションよりも長く生き続けているということです。そのため、ログイン時に 1.) Cookiedベースの認証セッションを持っている 2.) いくつかのセッション変数を設定する

私のセッション変数(2) "die"は、owinクッキーセッション変数の前に再ログインを強制し、私のアプリケーション全体を通して予期しない振る舞いを引き起こします。(人はログインしているが、実際にはログインしていない)

アップデート 3B

あるページで、quot;forms" の認証タイムアウトとセッション タイムアウトを一致させる必要があるというコメントを見かけました。通常、この 2 つは同期していますが、何らかの理由でこの 2 つが同期していないと考えています。

回避策のまとめ

1) 認証の前に必ずセッションを作成する。基本的にアプリケーションの起動時にセッションを作成します。 Session["Workaround"] = 0;

2) [実験] クッキーを持続させる場合、OWINのタイムアウト/長さがweb.configのsessionTimeoutより長いことを確認する(テスト中)。

どのように解決するのですか?

私も同じ問題に遭遇し、OWIN ASP.NETホスティングの実装に原因を追究しました。私は、それはバグだと言うでしょう。

いくつかの背景

私の発見は、これらのアセンブリバージョンに基づくものです。

  • Microsoft.Owin, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
  • Microsoft.Owin.Host.SystemWeb, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
  • System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

OWINはレスポンス・クッキー( Microsoft.Owin.ResponseCookieCollection ). この実装では、レスポンスヘッダーコレクションを直接ラップし、それに応じて セット-クッキー ヘッダを更新します。OWIN ASP.NETホスト( Microsoft.Owin.Host.SystemWeb ) は、ただラップするだけです。 System.Web.HttpResponse とそのヘッダコレクションをラップしているだけです。従って、OWINを通じて新しいクッキーが作成されると、レスポンス セット-クッキー ヘッダは直接変更されます。

しかし、ASP.NETはレスポンスCookieを扱うために、独自の抽象化を使用しています。これは System.Web.HttpResponse.Cookies として公開されています。 プロパティとして公開され、シールされたクラスによって実装されています。 System.Web.HttpCookieCollection . この実装では、レスポンス Set-Cookie ヘッダを直接ラップせず、いくつかの最適化と内部通知の一握りを使って、レスポンスオブジェクトに変更された状態を明示します。

次に、リクエストの寿命の後半で HttpCookieCollection が変更された状態がテストされます ( System.Web.HttpResponse.GenerateResponseHeadersForCookies() を使用します。 ) にシリアライズされ、クッキーは Set-Cookie ヘッダーに格納されます。このコレクションが特定の状態にある場合、Set-Cookieヘッダ全体がまずクリアされ、コレクションに保存されているCookieから再作成されます。

ASP.NETのセッションの実装では System.Web.HttpResponse.Cookiesを使用します。 プロパティを使用して、ASP.NET_SessionId Cookieを保存します。また、ASP.NETのセッション状態モジュールでいくつかの基本的な最適化があります( システム.Web.SessionState.SessionStateModule )の静的プロパティs_sessionEverSetを通して実装されたいくつかの基本的な最適化があります。あなたのアプリケーションでセッション状態に何かを格納する場合は、このモジュールは、各リクエストのためにもう少し作業を行います。


ログインの問題に戻る

これらすべての部品で、あなたのシナリオを説明することができます。

ケース 1 - セッションが設定されていない

System.Web.SessionState.SessionStateModule の場合、s_sessionEverSet プロパティは false です。セッションステートモジュールでセッションIDが生成されず System.Web.HttpResponse.Cookies コレクション状態は 変更されたと検出されない . この場合、OWINクッキーはブラウザに正しく送信され、ログインは機能します。

ケース2 - アプリケーションのどこかでセッションが使用されているが、ユーザーが認証しようとする前ではない場合

System.Web.SessionState.SessionStateModule の場合、s_sessionEverSetプロパティはtrueです。セッションIDの生成は SessionStateModule に、ASP.NET_SessionIdが追加されます。 System.Web.HttpResponse.Cookiesに追加されます。 コレクションに追加されますが、ユーザーのセッションが実際には空であるため、リクエストの有効期間の後半に削除されます。この場合 システム.Web.HttpResponse.Cookies コレクションの状態は が変更されたと検出されました。 そして セット-クッキー ヘッダは、Cookie がヘッダ値にシリアライズされる前に、まずクリアされます。

この場合、OWINレスポンスクッキーは失われ、ユーザーは認証されず、ログインページにリダイレクトされます。

ケース3 - ユーザーが認証しようとする前にセッションが使用される場合

System.Web.SessionState.SessionStateModule の場合、s_sessionEverSetプロパティはtrueです。セッションIDの生成は SessionStateModule に、ASP.NET_SessionIdが追加されます。 System.Web.HttpResponse.Cookiesに追加されます。 . の内部最適化により System.Web.HttpCookieCollection System.Web.HttpResponse.GenerateResponseHeadersForCookies() Set-Cookieヘッダが最初にクリアされていない が、更新されるだけです。

この場合、OWIN認証クッキーとASP.NET_SessionIdクッキーの両方がレスポンスで送信され、ログインが機能します。


クッキーに関するより一般的な問題

ご覧のように、この問題はより一般的で、ASP.NET セッションに限定されたものではありません。OWINを Microsoft.Owin.Host.SystemWeb を使用していて、あなたや何かが直接 System.Web.HttpResponse.Cookiesを使用しています。 コレクションが危険にさらされています。

例えば この作品 で、両方のクッキーが正しくブラウザに送信されます...

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";

    return View();
}

しかし ではありません。 で、OwinCookieは失われました...。

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";
    HttpContext.Response.Cookies.Remove("ASPCookie");

    return View();
}

いずれもVS2013、IISExpress、デフォルトのMVCプロジェクトテンプレートからテストしています。