I have a strange problem with using Owin cookie authentication.
When I start my IIS server authentication works perfectly fine on IE/Firefox and Chrome.
I started doing some testing with Authentication and logging in on different platforms and I have come up with a strange error. Sporadically the Owin framework / IIS just doesn't send any cookies to the browsers. I will type in a username and password which is correct the code runs but no cookie gets delivered to the browser at all. If I restart the server it starts working then at some point I will try login and again cookies stop getting delivered. Stepping over the code does nothing and throws no errors.
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);
}
}
}
});
And within my login procedure I have the following code:
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);
Update 1: It seems that one cause of the problem is when I add items to session the problems start. Adding something simple like Session.Content["ABC"]= 123
seems to create the problem.
What I can make out is as follows: 1) (Chrome)When I login I get ASP.NET_SessionId + my authentication cookie. 2) I go to a page that sets a session.contents... 3) Open a new browser (Firefox) and try login and it does not receive an ASP.NET_SessionId nor does it get a Authentication Cookie 4) Whilst the first browser has the ASP.NET_SessionId it continues to work. The minute I remove this cookie it has the same problem as all the other browsers I am working on ip address (10.x.x.x) and localhost.
Update 2: Force creation of ASPNET_SessionId
first on my login_load page before authentication with OWIN.
1) before I authenticate with OWIN I make a random Session.Content
value on my login page to start the ASP.NET_SessionId 2) then I authenticate and make further sessions 3) Other browsers seem to now work
This is bizarre. I can only conclude that this has something to do with ASP and OWIN thinking they are in different domains or something like that.
Update 3 - Strange behaviour between the two.
Additional strange behaviour identified - Timeout of Owin and ASP session is different. What I am seeing is that my Owin sessions are staying alive longer than my ASP sessions through some mechanism. So when logging in: 1.) I have a cookied based auth session 2.) I set a few session variables
My session variables(2) "die" before the owin cookie session variable forces re-login, which causes unexpected behaviour throughout my entire application. (Person is logged in but is not really logged in)
Update 3B
After some digging I saw some comments on a page that say the "forms" authentication timeout and session timeout need to match. I am thinking normally the two are in sync but for whatever reason the two are not in sync.
Summary of Workarounds
1) Always create a Session first before authentication. Basically create session when you start the application Session["Workaround"] = 0;
2) [Experimental] if you persist cookies make sure your OWIN timeout / length is longer than your sessionTimeout in your web.config (in testing)
ベストアンサー1
I have encountered the same problem and traced the cause to OWIN ASP.NET hosting implementation. I would say it's a bug.
Some background
My findings are based on these assembly versions:
- 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 uses it's own abstraction to work with response Cookies (Microsoft.Owin.ResponseCookieCollection). This implementation directly wraps response headers collection and accordingly updates Set-Cookie header. OWIN ASP.NET host (Microsoft.Owin.Host.SystemWeb) just wraps システム.Web.HttpResponseそして、それはヘッダーコレクションです。したがって、OWINを通じて新しいクッキーが作成されると、応答Cookie の設定ヘッダーが直接変更されます。
しかし、ASP.NETはレスポンスCookieを扱うために独自の抽象化も使用しています。これは次のように公開されています。システム.Web.HttpResponse.Cookiesプロパティとシールクラスによって実装されるシステム.Web.HttpCookieコレクションこの実装ではレスポンスをラップしませんCookie の設定ヘッダーを直接使用しますが、いくつかの最適化と少数の内部通知を使用して、変更された状態を応答オブジェクトに明示します。
そして、リクエストの存続期間の後半で、HTTPCookieコレクション変更された状態がテストされます(System.Web.HttpResponse.GenerateResponseHeadersForCookies())とクッキーはシリアル化され、Cookie の設定ヘッダー。このコレクションが特定の状態にある場合、まず Set-Cookie ヘッダー全体がクリアされ、コレクションに保存されている Cookie から再作成されます。
ASP.NETセッション実装では、システム.Web.HttpResponse.CookiesASP.NET_SessionId Cookie を保存するためのプロパティ。また、ASP.NET セッション状態モジュールにはいくつかの基本的な最適化があります (System.Web.SessionState.SessionStateModule) は、s_sessionEverSet という静的プロパティを通じて実装されます。これは、説明の必要がないほどです。アプリケーションでセッション状態に何かを保存する場合、このモジュールはリクエストごとにもう少し作業を行います。
ログインの問題に戻る
これらすべての要素があれば、シナリオを説明することができます。
ケース1 - セッションが設定されていない
System.Web.SessionState.SessionStateModule、s_sessionEverSetプロパティはfalseです。セッション状態モジュールによってセッションIDは生成されず、システム.Web.HttpResponse.Cookiesコレクションの状態は変更が検出されませんでしたこの場合、OWIN クッキーはブラウザに正しく送信され、ログインが機能します。
ケース 2 - セッションはアプリケーションのどこかで使用されたが、ユーザーが認証を試みる前に使用されていない
System.Web.SessionState.SessionStateModule、s_sessionEverSetプロパティがtrueの場合、セッションIDは次のように生成されます。セッション状態モジュール、ASP.NET_SessionIdが追加されますシステム.Web.HttpResponse.Cookiesコレクションは、ユーザーのセッションが実際には空であるため、リクエストの有効期間の後半で削除されます。この場合システム.Web.HttpResponse.Cookiesコレクションの状態は変更されたと検出そしてCookie の設定クッキーがヘッダー値にシリアル化される前に、まずヘッダーがクリアされます。
この場合、OWIN 応答 Cookie は「失われ」、ユーザーは認証されず、ログイン ページにリダイレクトされます。
ケース3 - ユーザーが認証を試みる前にセッションが使用される
System.Web.SessionState.SessionStateModule、s_sessionEverSetプロパティがtrueの場合、セッションIDは次のように生成されます。セッション状態モジュール、ASP.NET_SessionIdが追加されますシステム.Web.HttpResponse.Cookies内部最適化によりシステム.Web.HttpCookieコレクションそしてSystem.Web.HttpResponse.GenerateResponseHeadersForCookies() Set-Cookie ヘッダーは最初にクリアされませんただし更新のみです。
この場合、OWIN 認証 Cookie と ASP.NET_SessionId Cookie の両方が応答として送信され、ログインが機能します。
クッキーに関するより一般的な問題
ご覧のとおり、問題はより一般的であり、ASP.NETセッションに限定されません。OWINをホストしている場合は、Microsoft.Owin.Host.SystemWebそしてあなた/何かが直接使用していますシステム.Web.HttpResponse.Cookiesコレクションにはリスクが伴います。
例えばこれはうまくいく両方の Cookie がブラウザに正しく送信されます...
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 プロジェクト テンプレートからテストされました。