ASP.NET_SessionId + OWIN คุกกี้ไม่ส่งไปยังเบราว์เซอร์


145

ฉันมีปัญหาแปลก ๆ กับการใช้การตรวจสอบคุกกี้ของ Owin

เมื่อฉันเริ่มการรับรองความถูกต้องเซิร์ฟเวอร์ IIS ของฉันทำงานได้อย่างสมบูรณ์แบบบน IE / Firefox และ Chrome

ฉันเริ่มทำการทดสอบด้วย Authentication และเข้าสู่ระบบบนแพลตฟอร์มที่แตกต่างกันและฉันพบข้อผิดพลาดแปลก ๆ กรอบ / Owin เป็นระยะ ๆ ไม่ส่งคุกกี้ใด ๆ ไปยังเบราว์เซอร์ ฉันจะพิมพ์ชื่อผู้ใช้และรหัสผ่านที่ถูกต้องรหัสทำงาน แต่ไม่มีการส่งคุกกี้ไปยังเบราว์เซอร์เลย หากฉันรีสตาร์ทเซิร์ฟเวอร์มันจะเริ่มทำงานเมื่อถึงจุดหนึ่งฉันจะลองล็อกอินอีกครั้งและคุกกี้จะหยุดการส่งมอบอีกครั้ง การเหยียบรหัสไม่ทำอะไรเลยและไม่เกิดข้อผิดพลาด

 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 + คุกกี้การตรวจสอบสิทธิ์ของฉัน 2) ฉันไปที่หน้าที่ตั้งค่าเซสชันเนื้อหา ... 3) เปิดเบราว์เซอร์ใหม่ (Firefox) และลองเข้าสู่ระบบและไม่ได้รับ ASP.NET_SessionId และไม่ได้รับคุกกี้การตรวจสอบสิทธิ์ 4) ในขณะที่เบราว์เซอร์แรก มี ASP.NET_SessionId มันยังคงทำงานต่อไป นาทีที่ฉันลบคุกกี้นี้มันมีปัญหาเช่นเดียวกับเบราว์เซอร์อื่น ๆ ทั้งหมดที่ฉันใช้กับที่อยู่ IP (10.xxx) และ localhost

อัปเดต 2:บังคับให้สร้างรายการASPNET_SessionIdแรกในหน้าล็อกอินของฉันก่อนทำการตรวจสอบสิทธิ์ด้วย OWIN

1) ก่อนที่ฉันจะรับรองความถูกต้องกับ OWIN ฉันจะสร้างSession.Contentค่าสุ่มบนหน้าเข้าสู่ระบบของฉันเพื่อเริ่มต้น ASP.NET_SessionId 2) จากนั้นฉันจะตรวจสอบสิทธิ์และสร้างเซสชันเพิ่มเติม 3) เบราว์เซอร์อื่น ๆ

นี่มันแปลกประหลาด ฉันสามารถสรุปได้ว่าสิ่งนี้เกี่ยวข้องกับ ASP และ OWIN โดยคิดว่าพวกเขาอยู่ในโดเมนที่ต่างกันหรืออะไรทำนองนั้น

อัพเดท 3 - พฤติกรรมแปลก ๆ ระหว่างคนทั้งสอง

พฤติกรรมที่แปลกเพิ่มเติมที่ระบุ - การหมดเวลาของ Owin และเซสชัน ASP นั้นแตกต่างกัน สิ่งที่ฉันเห็นคือว่าเซสชัน Owin ของฉันมีชีวิตอยู่ได้นานกว่าเซสชัน ASP ของฉันผ่านกลไกบางอย่าง ดังนั้นเมื่อเข้าสู่ระบบ: 1. ) ฉันมีเซสชั่นรับรองความถูกต้องตามที่ปรุงไว้ 2. ) ฉันตั้งค่าตัวแปรเซสชันไม่กี่

ตัวแปรเซสชันของฉัน (2) "ตาย" ก่อนตัวแปรเซสชันคุกกี้ owin บังคับให้ลงชื่อเข้าใช้อีกครั้งซึ่งทำให้เกิดพฤติกรรมที่ไม่คาดคิดตลอดทั้งแอปพลิเคชันของฉัน (บุคคลนั้นเข้าสู่ระบบ แต่ไม่ได้เข้าสู่ระบบจริงๆ)

อัปเดต 3B

หลังจากการขุดบางครั้งฉันเห็นความคิดเห็นบางอย่างในหน้าเว็บที่ระบุว่า "ฟอร์ม" การหมดเวลาการตรวจสอบสิทธิ์และการหมดเวลาเซสชันต้องตรงกัน ฉันคิดว่าโดยทั่วไปทั้งสองจะซิงค์กัน แต่ด้วยเหตุผลใดก็ตามที่ทั้งสองไม่ตรงกัน

สรุปการแก้ไขปัญหา

1) สร้างเซสชันก่อนการรับรองความถูกต้องเสมอ สร้างเซสชันโดยทั่วไปเมื่อคุณเริ่มแอปพลิเคชันSession["Workaround"] = 0;

2) [ทดลอง] หากคุณยืนยันคุกกี้ตรวจสอบให้แน่ใจว่าการหมดเวลา / ความยาวของ OWIN ของคุณนั้นยาวกว่า sessionTimeout ของคุณใน web.config (ในการทดสอบ)


1
สามารถยืนยันได้ว่าการเพิ่มการเรียกเซสชันไปยัง ActionResult เข้าสู่ระบบและ ActionResult ExternalLogin สามารถแก้ไขปัญหานี้ได้ ฉันแน่ใจว่าต้องการเพียงสิ่งเดียว แต่ฉันมีทั้งคู่
สกอตต์

ขอบคุณ! ... การเพิ่มเซสชันใน ExternalLogin แก้ไขให้ฉัน ... นี่เป็นเวทย์มนตร์วิเศษ ... ฉันเสียเวลาไปแล้ว 6 ชั่วโมงในการตามล่าปัญหานี้ ...
xdev

คำตอบ:


159

ฉันพบปัญหาเดียวกันและสืบสาเหตุของการใช้งานโฮสติ้ง ASP.NET ของ OWIN ฉันจะบอกว่ามันเป็นข้อผิดพลาด

พื้นหลังบางส่วน

การค้นพบของฉันขึ้นอยู่กับเวอร์ชันการประกอบเหล่านี้:

  • Microsoft.Owin, รุ่น = 2.0.2.0, วัฒนธรรม = เป็นกลาง, PublicKeyToken = 31bf3856ad364e35
  • Microsoft.Owin.Host.SystemWeb, รุ่น = 2.0.2.0, วัฒนธรรม = เป็นกลาง, PublicKeyToken = 31bf3856ad364e35
  • System.Web, เวอร์ชัน = 4.0.0.0, วัฒนธรรม = เป็นกลาง, PublicKeyToken = b03f5f7f11d50a3a

OWIN ใช้นามธรรมเป็นของตัวเองในการทำงานกับการตอบสนองคุกกี้ ( Microsoft.Owin.ResponseCookieCollection ) การนำไปใช้งานนี้จะรวบรวมคอลเลกชันของส่วนหัวการตอบสนองโดยตรงและปรับปรุงส่วนหัวSet-Cookie โฮสต์ ASP.NET OWIN ( Microsoft.Owin.Host.SystemWeb ) เพียงแค่ล้อมSystem.Web.HttpResponseและคอลเล็กชันส่วนหัว ดังนั้นเมื่อมีการสร้างคุกกี้ใหม่ผ่าน OWIN ส่วนหัวSet-Cookie การตอบสนองจะเปลี่ยนไปโดยตรง

แต่ ASP.NET ก็ใช้สิ่งที่เป็นนามธรรมของตัวเองเพื่อทำงานกับการตอบสนองคุกกี้ นี้มีการสัมผัสกับเราเป็นSystem.Web.HttpResponse.CookiesคุณสมบัติและดำเนินการโดยระดับปิดผนึกSystem.Web.HttpCookieCollection การใช้งานนี้ไม่รวมส่วนหัวSet-Cookieการตอบสนองโดยตรง แต่ใช้การเพิ่มประสิทธิภาพบางอย่างและการแจ้งเตือนภายในจำนวนหนึ่งเพื่อแสดงรายการว่ามีการเปลี่ยนแปลงสถานะเป็นวัตถุตอบกลับ

จากนั้นจะมีช่วงปลายอายุการใช้งานซึ่งสถานะการเปลี่ยนแปลงของHttpCookieCollectionถูกทดสอบ ( System.Web.HttpResponse.GenerateResponseHeadersForCookies () ) และคุกกี้จะถูกทำให้เป็นอนุกรมกับส่วนหัวSet-Cookie หากคอลเล็กชันนี้อยู่ในสถานะเฉพาะบางส่วนส่วนหัว Set-Cookie ทั้งหมดจะถูกล้างและสร้างใหม่จากคุกกี้ที่เก็บในคอลเลกชัน

การใช้งานเซสชัน ASP.NET ใช้คุณสมบัติSystem.Web.HttpResponse.Cookiesเพื่อจัดเก็บคุกกี้ ASP.NET_SessionId นอกจากนี้ยังมีการเพิ่มประสิทธิภาพพื้นฐานในโมดูลสถานะเซสชัน ASP.NET ( System.Web.SessionState.SessionStateModule ) ที่ใช้งานผ่านคุณสมบัติคงที่ชื่อ s_sessionEverSet ซึ่งค่อนข้างอธิบายตนเอง หากคุณเคยเก็บบางสิ่งบางอย่างไว้ในสถานะเซสชันในแอปพลิเคชันของคุณโมดูลนี้จะทำงานได้มากขึ้นเล็กน้อยสำหรับแต่ละคำขอ


กลับไปที่ปัญหาการเข้าสู่ระบบของเรา

กับทุกสิ่งเหล่านี้สถานการณ์ของคุณสามารถอธิบายได้

กรณีที่ 1 - เซสชันไม่เคยถูกตั้งค่า

System.Web.SessionState.SessionStateModule , s_sessionEverSet คุณสมบัติเป็นเท็จ ไม่มีของเซสชั่น ID จะถูกสร้างโดยโมดูลภาครัฐและSystem.Web.HttpResponse.Cookiesรัฐคอลเลกชันจะตรวจไม่พบมีการเปลี่ยนแปลง ในกรณีนี้คุกกี้ OWIN จะถูกส่งไปยังเบราว์เซอร์อย่างถูกต้องและการเข้าสู่ระบบทำงาน

กรณีที่ 2 - เซสชันถูกใช้ที่ไหนสักแห่งในแอปพลิเคชัน แต่ไม่ใช่ก่อนที่ผู้ใช้จะพยายามตรวจสอบสิทธิ์

คุณสมบัติSystem.Web.SessionState.SessionStateModule , s_sessionEverSet เป็นจริง รหัสเซสชันถูกสร้างขึ้นโดยSessionStateModule ASP.NET_SessionId จะถูกเพิ่มลงในคอลเลกชันSystem.Web.HttpResponse.Cookiesแต่จะถูกลบออกในภายหลังในช่วงอายุการใช้งานที่ร้องขอเนื่องจากเซสชันของผู้ใช้ว่างเปล่า ในกรณีนี้ตรวจพบสถานะการรวบรวมSystem.Web.HttpResponse.Cookies เมื่อมีการเปลี่ยนแปลงและส่วนหัวSet-Cookieจะถูกล้างก่อนที่คุกกี้จะถูกทำให้เป็นอนุกรมตามค่าส่วนหัว

ในกรณีนี้คุกกี้ตอบกลับของ OWIN จะ "สูญหาย" และผู้ใช้จะไม่ได้รับการตรวจสอบสิทธิ์และถูกเปลี่ยนเส้นทางกลับไปที่หน้าเข้าสู่ระบบ

กรณีที่ 3 - เซสชันถูกใช้ก่อนที่ผู้ใช้จะพยายามพิสูจน์ตัวตน

คุณสมบัติSystem.Web.SessionState.SessionStateModule , s_sessionEverSet เป็นจริง 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 เริ่มต้น


7
ฉันใช้เวลาสองสามวันในการพยายามแก้ไขข้อบกพร่องและแก้ไขปัญหานี้ในสภาพแวดล้อมการทดสอบของเรา วิธีแก้ปัญหาที่ฉันพบเท่านั้นเป็นสิ่งเดียวกับที่คุณแนะนำ ฉันได้รายงานปัญหาไปยัง katanaproject ... katanaproject.codeplex.com/workitem/197ดังนั้นอาจมีบางคนแสดงความคิดเห็นที่นั่น
Tomas Dolezal

11
นี่เป็นข้อบกพร่องที่ร้ายแรงโดยเฉพาะอย่างยิ่งเนื่องจากพวกเขาบรรจุแม่แบบสำหรับ vs2013
Piotr Stulinski

2
สำหรับผู้ที่ต้องการตรวจสอบเพิ่มเติมฉันได้สร้างโครงการทดสอบที่ github.com/Neilski/IdentityBugDemo
Neilski

1
พบปัญหานี้เนื่องจากการใช้ Controller.TempData ซึ่งใช้ Session เป็นแหล่งสำรองข้อมูล สามารถทำซ้ำการไม่สามารถลงชื่อเข้าใช้ได้อย่างง่ายดายหากไม่มีคุกกี้ ASP_NET.SessionId จากคำขอก่อนหน้า
kingdango

2
ที่สุด! ช่างเป็นปัญหาที่แปลกขนาดนี้ ขอบคุณ. นี่ยังเป็นปัญหาในอีกสองปีหลังจากเขียนคำตอบนี้
Spivonious

43

เริ่มต้นด้วยการวิเคราะห์ที่ยอดเยี่ยมโดย @TomasDolezal ฉันได้ดูทั้งแหล่งที่มาของ Owin และ System.Web

ปัญหาคือว่า System.Web มีแหล่งข้อมูลหลักของตัวเองและนั่นไม่ใช่ส่วนหัว Set-Cookie Owin รู้เฉพาะส่วนหัว Set-Cookie เท่านั้น วิธีแก้ปัญหาคือตรวจสอบให้แน่ใจว่ามีการตั้งค่าคุกกี้ใด ๆ ของ Owin ไว้ในHttpContext.Current.Response.Cookiesคอลเลกชันด้วย

ผมได้ทำมิดเดิลแวร์ขนาดเล็ก ( แหล่งที่มา , nuget ) ที่ไม่ตรงกับที่ซึ่งมีวัตถุประสงค์เพื่อจะวางไว้ข้างต้นลงทะเบียนคุกกี้มิดเดิลแวร์

app.UseKentorOwinCookieSaver();

app.UseCookieAuthentication(new CookieAuthenticationOptions());

1
จะลองทำดู ตั้งแต่ asp.net Identity 2.2.0-alpha1 ฉันเริ่มมีปัญหาไม่เพียงแค่ในการเข้าสู่ระบบ แต่เมื่อทำการล็อกผู้ใช้ (ผู้ใช้จะไม่ออกจากระบบเมื่อคลิกออกจากระบบ | โดยทั่วไปในกรณีที่เปิดเว็บไซต์ทิ้งไว้นาน โดยไม่ต้องทำอะไร |) .. และหลังจากการตั้งค่าเซสชั่นก่อนที่ผู้ใช้เข้าสู่ระบบในการแก้ไขปัญหาการเข้าสู่ระบบ แต่ปัญหาการออกจากระบบยังคงมีอยู่ .. ขอบคุณสำหรับความพยายามของคุณ .. โดยวิธีการมีอะไรที่ฉันควรทำยกเว้นการติดตั้ง แพคเกจ?
wooer

คุณต้องเปิดใช้งานด้วยapp.UseKentorCookieMiddlewareSaver();ใน Startup.Auth.cs มันควรจัดการกับการล้างคุกกี้ออกจากระบบด้วย
Anders Abel

ขอบคุณ Anders Abel มากทั้งการเข้าสู่ระบบและการออกจากระบบใช้งานได้ดีในขณะนี้ แต่รหัสในความต้องการแสดงความคิดเห็นดังกล่าวข้างต้นที่จะเปลี่ยนแปลง (เพราะผมทำตามมัน :) ไม่ประสบความสำเร็จใด ๆ ) จะเป็น: app.UseKentorOwinCookieSaver()และอาจจะรวมอยู่ในคำตอบเดิมในแพคเกจที่หน้า GitHub
wooer

1
ขอบคุณที่สังเกตเห็นเอกสารที่ไม่ถูกต้อง มันได้รับการแก้ไขแล้วในหน้า GitHub แต่ฉันได้อัปเดตคำตอบของฉันที่นี่เช่นกัน
Anders Abel

@AndersAbel ฉันกำลังพยายามเพิ่มการสมัครสมาชิก Meetup สำหรับโครงการ github นี้: github.com/owin-middleware/OwinOAuthProviders '' ฉันเพิ่ม Asana เมื่อวันก่อนและไม่มีปัญหา แต่ด้วยเหตุผลบางอย่างกับ Meetup, AuthenticationManager.GetExternalLoginInfoAsync () ที่รอคอยในบัญชี // ExternalLoginCallback จะส่งคืน null ขออภัยแพคเกจ NuGet ของคุณไม่ได้แก้ปัญหาของฉัน ฉันสงสัยว่าถ้าคุณมีเวลาทบทวนกับฉันเพราะคุณอาจแก้ไขปัญหาได้ดีขึ้นและผลักดันโครงการของคุณ
Anthony Ruffino

42

ในระยะสั้นผู้จัดการ .NET คุกกี้จะชนะมากกว่าผู้จัดการ OWIN คุกกี้และคุกกี้ทับตั้งอยู่บนชั้น การแก้ไขคือการใช้ระดับ SystemWebCookieManager ให้เป็นวิธีแก้ปัญหาในโครงการ Katana ที่นี่ คุณต้องใช้คลาสนี้หรือคลาสที่คล้ายกันซึ่งจะบังคับให้ OWIN ใช้ตัวจัดการคุกกี้ของ. NET ดังนั้นจึงไม่มีความไม่สอดคล้องกัน :

public class SystemWebCookieManager : ICookieManager
{
    public string GetRequestCookie(IOwinContext context, string key)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
        var cookie = webContext.Request.Cookies[key];
        return cookie == null ? null : cookie.Value;
    }

    public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

        bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
        bool pathHasValue = !string.IsNullOrEmpty(options.Path);
        bool expiresHasValue = options.Expires.HasValue;

        var cookie = new HttpCookie(key, value);
        if (domainHasValue)
        {
            cookie.Domain = options.Domain;
        }
        if (pathHasValue)
        {
            cookie.Path = options.Path;
        }
        if (expiresHasValue)
        {
            cookie.Expires = options.Expires.Value;
        }
        if (options.Secure)
        {
            cookie.Secure = true;
        }
        if (options.HttpOnly)
        {
            cookie.HttpOnly = true;
        }

        webContext.Response.AppendCookie(cookie);
    }

    public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        AppendResponseCookie(
            context,
            key,
            string.Empty,
            new CookieOptions
            {
                Path = options.Path,
                Domain = options.Domain,
                Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
            });
    }
}

ในการเริ่มต้นแอปพลิเคชันของคุณเพียงกำหนดมันเมื่อคุณสร้างการพึ่งพา OWIN ของคุณ:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    ...
    CookieManager = new SystemWebCookieManager()
    ...
});

มีคำตอบที่คล้ายกันไว้ที่นี่ แต่ไม่รวมรหัสฐานทั้งหมดที่จำเป็นในการแก้ปัญหาดังนั้นฉันเห็นความจำเป็นที่จะต้องเพิ่มที่นี่เพราะลิงก์ภายนอกไปยังโครงการ Katana อาจลงไปและสิ่งนี้ควรลงมืออย่างเต็มที่ เป็นวิธีแก้ปัญหาที่นี่เช่นกัน


ขอบคุณมันทำงานฉัน แต่ฉันยังล้างเซสชั่นทั้งหมดโดยการเรียก ControllerContext.HttpContext.Session.RemoveAll () นี้; ในฟังก์ชั่น externallogincallback
adnan

ใช้กับASP.NET Webforms 4.6.1หรือไม่ webApp ของฉันใช้ASP.NET Webforms, OWIN, ADFS
Kiquenet

@Kiquenet แอปเว็บของคุณใช้คุกกี้ OWIN หรือไม่ ใช่แล้ว
Alexandru

ในรหัสStartup.ConfigureAuthเรามีapp.UseCookieAuthenticationและapp.UseWsFederationAuthenticationในที่สุด app.UseStageMarker
Kiquenet

@Alexandru คุณอาจพิจารณาการแก้ไขทีมของฉันพบข้อผิดพลาดนี้และหายากและเป็นการสุ่มซ่อนตัวจากเราผ่านสภาพแวดล้อม DEV และ UAT อ้างจากคำตอบของคุณไม่ได้ทำให้เรา: ". ผู้จัดการคุกกี้ NET. จะชนะเสมอ" ซึ่งจะง่ายต่อการค้นหาและแก้ไขหากคุกกี้ OWIN ถูกเขียนทับไม่มีมิดเดิลแวร์ OIDC ของเราจะทำให้มันออกจากเวิร์คสเตชั่น dev ของเรา แต่การสุ่มหมายถึงข้อผิดพลาดทำให้ทุกอย่างเป็นไปได้ในการผลิตเป็นเวลา 2 วันก่อนที่มันจะโจมตีเราในระดับ (ครึ่งหนึ่งของการใช้งานภายในของเราไม่สามารถเข้าสู่ระบบผ่าน AAD) รังเกียจไหมถ้าฉันลบคำว่า "เสมอ" ออกจากคำตอบของคุณ?
yzorg

17

ทีม Katana ตอบคำถามที่ Tomas Dolezar ยกมาและโพสต์เอกสารเกี่ยวกับการแก้ไขปัญหา :

วิธีแก้ไขปัญหาแบ่งออกเป็นสองประเภท หนึ่งคือการกำหนดค่า System.Web อีกครั้งเพื่อหลีกเลี่ยงการใช้คอลเลกชัน Response.Cookies และเขียนทับคุกกี้ OWIN วิธีอื่นคือการกำหนดค่าองค์ประกอบ OWIN ที่ได้รับผลกระทบใหม่เพื่อให้พวกเขาเขียนคุกกี้โดยตรงไปยังคอลเลกชันของ System.Web Response.Cookies

  • ตรวจสอบให้แน่ใจว่ามีการสร้างเซสชันก่อนการรับรองความถูกต้อง: ความขัดแย้งระหว่างคุกกี้ System.Web และ Katana นั้นเป็นไปตามคำขอดังนั้นอาจเป็นไปได้ว่าแอปพลิเคชันจะสร้างเซสชันตามคำขอบางอย่างก่อนที่จะมีการตรวจสอบสิทธิ์ สิ่งนี้ควรทำง่ายเมื่อผู้ใช้มาถึงครั้งแรก แต่อาจเป็นการยากกว่าที่จะรับประกันในภายหลังเมื่อเซสชันหรือคุกกี้รับรองความถูกต้องหมดอายุและ / หรือจำเป็นต้องรีเฟรช
  • ปิดการใช้งาน SessionStateModule - หากแอปพลิเคชันไม่ได้ใช้ข้อมูลเซสชัน แต่โมดูลเซสชันยังคงตั้งค่าคุกกี้ที่ทำให้เกิดข้อขัดแย้งข้างต้นคุณอาจพิจารณาปิดใช้งานโมดูลสถานะเซสชัน
  • กำหนดค่าใหม่ CookieAuthenticationMiddleware เพื่อเขียนโดยตรงไปยังคอลเลกชันคุกกี้ของ System.Web
app.UseCookieAuthentication(new CookieAuthenticationOptions
                                {
                                    // ...
                                    CookieManager = new SystemWebCookieManager()
                                });

ดูการใช้ SystemWebCookieManager จากเอกสาร (ลิงก์ด้านบน)

ข้อมูลเพิ่มเติมที่นี่

แก้ไข

ด้านล่างขั้นตอนที่เราดำเนินการเพื่อแก้ไขปัญหา ทั้ง 1. และ 2. แก้ปัญหาแยกกัน แต่เราตัดสินใจใช้ทั้งสองกรณี:

1. ใช้SystemWebCookieManager

2. ตั้งค่าตัวแปรเซสชัน:

protected override void Initialize(RequestContext requestContext)
{
    base.Initialize(requestContext);

    // See http://stackoverflow.com/questions/20737578/asp-net-sessionid-owin-cookies-do-not-send-to-browser/
    requestContext.HttpContext.Session["FixEternalRedirectLoop"] = 1;
}

(หมายเหตุด้านข้าง: วิธีการเตรียมใช้งานข้างต้นเป็นสถานที่ตรรกะสำหรับการแก้ไขเนื่องจากฐานเริ่มต้นทำให้เซสชันพร้อมใช้งานอย่างไรก็ตามการแก้ไขอาจถูกนำมาใช้ในภายหลังเพราะใน OpenId มีการร้องขอที่ไม่ระบุชื่อก่อนจากนั้นเปลี่ยนเส้นทางไปยังผู้ให้บริการ OpenId ไปที่แอพปัญหาจะเกิดขึ้นหลังจากการเปลี่ยนเส้นทางกลับไปที่แอพในขณะที่การแก้ไขตั้งค่าตัวแปรเซสชันแล้วในระหว่างการร้องขอที่ไม่ระบุชื่อครั้งแรกจึงแก้ไขปัญหาก่อนที่การเปลี่ยนเส้นทางกลับจะเกิดขึ้น)

แก้ไข 2

คัดลอกวางจากโครงการ Katana 2016/05/14:

เพิ่มสิ่งนี้:

app.UseCookieAuthentication(new CookieAuthenticationOptions
                                {
                                    // ...
                                    CookieManager = new SystemWebCookieManager()
                                });

...และนี่:

public class SystemWebCookieManager : ICookieManager
{
    public string GetRequestCookie(IOwinContext context, string key)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
        var cookie = webContext.Request.Cookies[key];
        return cookie == null ? null : cookie.Value;
    }

    public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

        bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
        bool pathHasValue = !string.IsNullOrEmpty(options.Path);
        bool expiresHasValue = options.Expires.HasValue;

        var cookie = new HttpCookie(key, value);
        if (domainHasValue)
        {
            cookie.Domain = options.Domain;
        }
        if (pathHasValue)
        {
            cookie.Path = options.Path;
        }
        if (expiresHasValue)
        {
            cookie.Expires = options.Expires.Value;
        }
        if (options.Secure)
        {
            cookie.Secure = true;
        }
        if (options.HttpOnly)
        {
            cookie.HttpOnly = true;
        }

        webContext.Response.AppendCookie(cookie);
    }

    public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        AppendResponseCookie(
            context,
            key,
            string.Empty,
            new CookieOptions
            {
                Path = options.Path,
                Domain = options.Domain,
                Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
            });
    }
}

ฉันพบคำตอบนี้ตรงไปตรงมามากขึ้นและง่ายต่อการแก้ไขปัญหา ขอบคุณ - บางทีฉันอาจพูดอย่างกระทันหัน นี่ไม่ได้แก้ปัญหาของฉัน
JCS

@JCS รวมขั้นตอนที่เราดำเนินการเพื่อแก้ไขปัญหา คุณค้นพบว่าปัญหาของคุณเกี่ยวข้องหรือไม่
thomius

ฉันใช้ Web Api 2 + Owin middleware + redis cache สำหรับจัดการเซสชั่นสำหรับการตรวจสอบสิทธิ์ ฉันพยายามใช้ SystemWebCookieManager และมันไม่ได้แก้ปัญหาที่ฉันมีในขณะที่คุกกี้ auth ไม่ได้ถูกตั้งค่า ใช้ "UseKentorOwinCookieSaver" แก้ไขได้ แต่ฉันไม่ชอบมากเกินไปของการพึ่งพาภายนอกพิเศษ ...
JCS

การล้างเซสชั่นทำงานสำหรับฉัน ไม่จำเป็นต้องพึ่งพาภายนอก ใส่นี้ControllerContext.HttpContext.Session.RemoveAll();ของคุณในการดำเนินการก่อนที่จะเรียกExternalLogin() ChallengeResult()ฉันไม่รู้ว่ามันเป็นทางออกที่ดีที่สุด แต่ก็ง่ายที่สุด
Alisson

1
@chemitaxis แน่นอนเพียงรับทราบ?.(ตัวดำเนินการแบบไม่มีเงื่อนไข) ใช้ได้เฉพาะใน C # 6
Alisson

5

มีการให้คำตอบไว้แล้ว แต่ใน 3.1.0 นั้นมีคลาส SystemWebChunkingCookieManager ซึ่งสามารถใช้ได้

https://github.com/aspnet/AspNetKatana/blob/dev/src/Microsoft.Owin.Host.SystemWeb/SystemWebChunkingCookieManager.cs

https://raw.githubusercontent.com/aspnet/AspNetKatana/c33569969e79afd9fb4ec2d6bdff877e376821b2/src/Microsoft.Owin.Host.SystemWeb/SystemWebChunkingCookieManager.cs

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    ...
    CookieManager = new SystemWebChunkingCookieManager()
    ...
});

นี่ยังเป็นปัญหาใน 3.1.0 หรือไม่?
cyberconte

1
ใช่มันยังคงเป็นปัญหาใน 3.1.0 สำหรับฉันและต้องการตัวจัดการคุกกี้นี้เนื่องจากค่าเริ่มต้นยังคงเป็น ChunkingCookieManager
jonmeyer

สามารถใช้ที่ไหน แล้วยังไง?
Simon_Weaver

@ Jonmeyer ขอบคุณ ฉันคิดว่าเมื่อวานนี้ฉันพลาดความแตกต่างระหว่าง SystemCCM และ CCM ดังนั้นฉันจะตรวจสอบเรื่องนี้อย่างแน่นอน
Simon_Weaver

แม้หลังจากเพิ่มบรรทัดข้างต้นมันไม่ทำงานสำหรับฉัน ฉันใช้เวอร์ชั่น 3.1.0 ส่วนใหญ่ฉันสามารถเข้าสู่ระบบครั้งแรก แต่หลังจากออกจากระบบมันไม่อนุญาตให้ฉันเข้าสู่ระบบ
Mitin Dixit

3

หากคุณกำลังตั้งค่าคุกกี้ในมิดเดิลแวร์ OWIN ด้วยตัวคุณเองOnSendingHeadersดูเหมือนว่าการใช้จะทำให้เกิดปัญหาได้

ตัวอย่างเช่นการใช้รหัสด้านล่างowinResponseCookie2จะถูกตั้งค่าแม้ว่าowinResponseCookie1จะไม่:

private void SetCookies()
{
    var owinContext = HttpContext.GetOwinContext();
    var owinResponse = owinContext.Response;

    owinResponse.Cookies.Append("owinResponseCookie1", "value1");

    owinResponse.OnSendingHeaders(state =>
    {
        owinResponse.Cookies.Append("owinResponseCookie2", "value2");
    },
    null);

    var httpResponse = HttpContext.Response;
    httpResponse.Cookies.Remove("httpResponseCookie1");
}

3

ฉันประสบปัญหาคล้ายกันกับVisual Studio 2017และ. net MVC 5.2.4 การอัปเดต Nuget Microsoft.Owin.Security.Googleเป็นเวอร์ชันล่าสุดซึ่งปัจจุบันเป็น4.0.1สำหรับฉัน! หวังว่าสิ่งนี้จะช่วยให้ใครบางคน!


1
บันทึกเบคอนของฉันในอันนี้! มีปัญหากับ Android Chrome โดยเฉพาะการสูญเสียการรับรองความถูกต้องแบบสุ่ม ไม่มีอะไรในกระทู้นี้ที่ทำงาน ฉันใช้ VS2019 และ ASP MVC 5
zfrank

2

โซลูชันรหัสบรรทัดเดียวที่เร็วที่สุด:

HttpContext.Current.Session["RunSession"] = "1";

เพียงเพิ่มบรรทัดนี้ก่อนวิธี CreateIdentity:

HttpContext.Current.Session["RunSession"] = "1";
var userIdentity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);
_authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = rememberLogin }, userIdentity);

1
คุณใส่รหัสนี้HttpContext.Current.Session["RunSession"] = "1";ที่ไหน ในGloba.asax Session_Start ?
Kiquenet

1
ในความเป็นจริงมันเป็นวิธีที่ง่ายที่สุดและเร็วที่สุดที่มีอยู่และจนกว่าจะแก้ปัญหาได้จะไม่รวมอยู่ใน Framework (ประกาศแล้วว่าจะ) - ตัวอย่างเช่นฉันจะชอบหนึ่งซับแทนที่จะเป็นคลาส + กลุ่มพึ่งพา . การแก้ปัญหานี้ต่ำกว่า IMHO
Der Zinger

ฉันเพิ่มใน AuthManager ของฉันที่ด้านบนของวิธี IssueAuthToken
Alexander Trofimov

1

ฉันมีอาการแบบเดียวกันกับส่วนหัวของ Set-Cookie ที่ไม่ได้ถูกส่ง แต่ไม่มีคำตอบใดที่ช่วยฉันได้ ทุกอย่างทำงานบนเครื่องท้องถิ่นของฉัน แต่เมื่อปรับใช้กับการผลิตส่วนหัวชุดคุกกี้จะไม่ได้รับการตั้งค่า

ปรากฎว่าเป็นการรวมกันของการใช้งานแบบกำหนดเองCookieAuthenticationMiddlewareกับ WebApi พร้อมกับการสนับสนุนการบีบอัด WebApi

โชคดีที่ฉันใช้ ELMAH ในโครงการซึ่งให้ข้อยกเว้นนี้กับฉันด้วย:

System.Web.HttpException Server ไม่สามารถผนวกส่วนหัวหลังจากที่ส่งส่วนหัว HTTP แล้ว

ซึ่งนำฉันไปสู่ปัญหา GitHubนี้

โดยทั่วไปถ้าคุณมีการติดตั้งที่แปลกเช่นเหมืองที่คุณต้องการจะบีบอัดปิดการใช้งานสำหรับตัวควบคุม WebAPI ของคุณ / OwinServerCompressionHandlerวิธีการที่ชุดคุกกี้หรือลอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.