ASP.NET_SessionId + OWIN Cookies không gửi tới trình duyệt


145

Tôi gặp vấn đề lạ khi sử dụng xác thực cookie Owin.

Khi tôi khởi động xác thực máy chủ IIS của tôi hoạt động hoàn toàn tốt trên IE / Firefox và Chrome.

Tôi bắt đầu thực hiện một số thử nghiệm với Xác thực và đăng nhập trên các nền tảng khác nhau và tôi đã gặp phải một lỗi lạ. Một cách ngẫu nhiên, khung Owin / IIS không gửi bất kỳ cookie nào tới trình duyệt. Tôi sẽ nhập tên người dùng và mật khẩu đúng mã đang chạy nhưng không có cookie nào được gửi đến trình duyệt cả. Nếu tôi khởi động lại máy chủ thì nó bắt đầu hoạt động, đến một lúc nào đó tôi sẽ thử đăng nhập và một lần nữa cookie sẽ ngừng được giao. Bước qua mã không làm gì và ném không có lỗi.

 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);
                     }
                 }
               }
        });

Và trong thủ tục đăng nhập của tôi, tôi có đoạn mã sau:

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);

Cập nhật 1: Dường như một nguyên nhân của vấn đề là khi tôi thêm các mục vào phiên giao dịch vấn đề bắt đầu. Thêm một cái gì đó đơn giản như Session.Content["ABC"]= 123dường như để tạo ra vấn đề.

Những gì tôi có thể thực hiện như sau: 1) (Chrome) Khi tôi đăng nhập, tôi nhận được ASP.NET_SessionId + cookie xác thực của mình. 2) Tôi đi đến một trang đặt session.contents ... 3) Mở trình duyệt mới (Firefox) và thử đăng nhập và nó không nhận được ASP.NET_SessionId và cũng không nhận được Cookie xác thực 4) trong khi trình duyệt đầu tiên Có ASP.NET_SessionId nó tiếp tục hoạt động. Ngay khi tôi gỡ bỏ cookie này, nó có cùng một vấn đề với tất cả các trình duyệt khác mà tôi đang làm việc trên địa chỉ IP (10.xxx) và localhost.

Cập nhật 2: Tạo lực lượngASPNET_SessionId lần đầu tiên trên trang login_load của tôi trước khi xác thực bằng OWIN.

1) trước khi tôi xác thực với OWIN, tôi tạo ngẫu nhiên Session.Content giá trị trên trang đăng nhập của mình để bắt đầu ASP.NET_SessionId 2) sau đó tôi xác thực và thực hiện các phiên tiếp theo 3) Các trình duyệt khác dường như đã hoạt động

Điều này thật kỳ quái. Tôi chỉ có thể kết luận rằng điều này có liên quan đến ASP và OWIN khi nghĩ rằng chúng thuộc các lĩnh vực khác nhau hoặc đại loại như thế.

Cập nhật 3 - Hành vi kỳ lạ giữa hai người.

Hành vi lạ khác được xác định - Thời gian chờ của phiên Owin và ASP là khác nhau. Những gì tôi đang thấy là các phiên Owin của tôi tồn tại lâu hơn các phiên ASP của tôi thông qua một số cơ chế. Vì vậy, khi đăng nhập: 1.) Tôi có phiên auth dựa trên cookied 2.) Tôi đặt một vài biến phiên

Biến phiên của tôi (2) "chết" trước khi biến phiên của phiên owin buộc phải đăng nhập lại, điều này gây ra hành vi không mong muốn trong toàn bộ ứng dụng của tôi. (Người đã đăng nhập nhưng không thực sự đăng nhập)

Cập nhật 3B

Sau khi đào bới, tôi thấy một số bình luận trên một trang cho biết thời gian chờ xác thực "biểu mẫu" và thời gian chờ phiên cần khớp. Tôi đang nghĩ bình thường hai người không đồng bộ nhưng vì lý do gì hai người không đồng bộ.

Tóm tắt cách giải quyết

1) Luôn tạo Phiên trước khi xác thực. Về cơ bản tạo phiên khi bạn khởi động ứng dụngSession["Workaround"] = 0;

2) [Thử nghiệm] nếu bạn duy trì cookie, hãy đảm bảo thời gian chờ / thời gian OWIN của bạn dài hơn sessionTimeout trong web.config (đang thử nghiệm)


1
Có thể xác nhận rằng việc thêm một cuộc gọi phiên vào ActionResult Đăng nhập và ActionResult ExternalLogin đã khắc phục vấn đề này. Tôi chắc chắn chỉ có một là cần thiết nhưng tôi có cả hai vị trí.
Scott

Cảm ơn bạn ... Thêm phiên trong ExternalLogin cố định nó cho tôi ... đây là voodoo kỳ diệu ... tôi đã lãng phí 6 giờ để săn vấn đề này xuống ..
xdev

Câu trả lời:


159

Tôi đã gặp phải vấn đề tương tự và truy tìm nguyên nhân để triển khai lưu trữ OWIN ASP.NET. Tôi sẽ nói đó là một lỗi.

Một số nền tảng

Phát hiện của tôi dựa trên các phiên bản lắp ráp này:

  • Microsoft.Owin, Phiên bản = 2.0.2.0, Văn hóa = trung tính, PublicKeyToken = 31bf3856ad364e35
  • Microsoft.Owin.Host.SystemWeb, Phiên bản = 2.0.2.0, Văn hóa = trung lập, PublicKeyToken = 31bf3856ad364e35
  • System.Web, Phiên bản = 4.0.0.0, Văn hóa = trung tính, PublicKeyToken = b03f5f7f11d50a3a

OWIN sử dụng tính trừu tượng của chính nó để làm việc với Cookies phản hồi ( Microsoft.Owin.ResponseCookieCollection ). Việc triển khai này trực tiếp bao bọc bộ sưu tập tiêu đề phản hồi và theo đó cập nhật tiêu đề Set-Cookie . Máy chủ OWIN ASP.NET ( Microsoft.Owin.Host.SystemWeb ) chỉ bao bọc System.Web.HttpResponse và đó là bộ sưu tập tiêu đề. Vì vậy, khi cookie mới được tạo thông qua OWIN, tiêu đề Set-Cookie phản hồi sẽ được thay đổi trực tiếp.

Nhưng ASP.NET cũng sử dụng sự trừu tượng của chính nó để làm việc với Cookies phản hồi. Điều này được hiển thị với chúng tôi dưới dạng thuộc tính System.Web.HttpResponse.Cookies và được triển khai bởi lớp kín System.Web.HttpCookieCollection . Việc triển khai này không bao gồm trực tiếp tiêu đề Set-Cookie mà sử dụng một số tối ưu hóa và một số thông báo nội bộ để hiển thị trạng thái đã thay đổi thành đối tượng phản hồi.

Sau đó, có một điểm trễ trong thời gian yêu cầu trong đó trạng thái thay đổi của httpCookieCollection được kiểm tra ( System.Web.HttpResponse.GenerateResponseHeadersForCookies () ) và cookie được tuần tự hóa thành tiêu đề Set-Cookie . Nếu bộ sưu tập này ở một số trạng thái cụ thể, toàn bộ tiêu đề Set-Cookie trước tiên sẽ bị xóa và được tạo lại từ các cookie được lưu trữ trong bộ sưu tập.

Triển khai phiên ASP.NET sử dụng thuộc tính System.Web.HttpResponse.Cookies để lưu trữ cookie ASP.NET_SessionId. Ngoài ra, có một số tối ưu hóa cơ bản trong mô-đun trạng thái phiên ASP.NET ( System.Web.SessionState.SessionStateModule ) được triển khai thông qua thuộc tính tĩnh có tên s_sessionEverSet, nó khá tự giải thích. Nếu bạn từng lưu trữ một cái gì đó vào trạng thái phiên trong ứng dụng của mình, mô-đun này sẽ thực hiện thêm một chút công việc cho mỗi yêu cầu.


Quay lại vấn đề đăng nhập của chúng tôi

Với tất cả các phần này, kịch bản của bạn có thể được giải thích.

Trường hợp 1 - Phiên không bao giờ được đặt

Thuộc tính System.Web.SessionState.SessionStateModule , s_sessionEverSet là sai. Không có id phiên nào được tạo bởi mô-đun trạng thái phiên và trạng thái bộ sưu tập System.Web.HttpResponse.Cookies không được phát hiện khi thay đổi . Trong trường hợp này, cookie OWIN được gửi chính xác đến trình duyệt và đăng nhập hoạt động.

Trường hợp 2 - Phiên được sử dụng ở đâu đó trong ứng dụng, nhưng không phải trước khi người dùng cố gắng xác thực

Thuộc tính System.Web.SessionState.SessionStateModule , s_sessionEverSet là đúng. Id phiên được tạo bởi SessionStateModule , ASP.NET_SessionId được thêm vào bộ sưu tập System.Web.HttpResponse.Cookies nhưng sau đó nó bị xóa trong thời gian yêu cầu vì phiên của người dùng thực sự trống. Trong trường hợp này, trạng thái bộ sưu tập System.Web.HttpResponse.Cookies được phát hiện là đã thay đổi và tiêu đề Set-Cookie được xóa trước tiên trước khi cookie được nối tiếp thành giá trị tiêu đề.

Trong trường hợp này, cookie phản hồi của OWIN bị "mất" và người dùng không được xác thực và được chuyển hướng trở lại trang đăng nhập.

Trường hợp 3 - Phiên được sử dụng trước khi người dùng cố gắng xác thực

Thuộc tính System.Web.SessionState.SessionStateModule , s_sessionEverSet là đúng. Id phiên được tạo bởi SessionStateModule , ASP.NET_SessionId được thêm vào System.Web.HttpResponse.Cookies . Do tối ưu hóa nội bộ trong System.Web.HttpCookieCollectionSystem.Web.HttpResponse.GenerateResponseHeadersForCookies () Tiêu đề Set-Cookie không được xóa đầu tiên mà chỉ được cập nhật.

Trong trường hợp này, cả cookie xác thực OWIN và cookie ASP.NET_SessionId đều được gửi trong phản hồi và đăng nhập hoạt động.


Vấn đề chung hơn với cookie

Như bạn có thể thấy vấn đề chung hơn và không giới hạn trong phiên ASP.NET. Nếu bạn đang lưu trữ OWIN thông qua Microsoft.Owin.Host.SystemWeb và bạn / một cái gì đó đang trực tiếp sử dụng bộ sưu tập System.Web.HttpResponse.Cookies, bạn sẽ gặp rủi ro.

Ví dụ: điều này hoạt động và cả hai cookie được gửi chính xác đến trình duyệt ...

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

    return View();
}

Nhưng điều này không và OwinCookie bị "mất" ...

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

    return View();
}

Cả hai đều được thử nghiệm từ VS2013, IISExpress và mẫu dự án MVC mặc định.


7
Tôi đã dành vài ngày để cố gắng gỡ lỗi và giải quyết vấn đề này trong môi trường thử nghiệm của chúng tôi. Cách giải quyết duy nhất tôi tìm thấy giống như bạn đã đề xuất (cài đặt phiên trước khi người dùng xác thực). Tôi đã báo cáo vấn đề với katanaproject ... katanaproject.codeplex.com/workitem/197 , vì vậy có lẽ ai đó sẽ bình luận ở đó.
Tomas Dolezal

11
Đây là một lỗ hổng khá nghiêm trọng, đặc biệt là vì họ đã đóng gói mẫu cho vs2013.
Piotr Stulinski

2
Đối với bất kỳ ai muốn điều tra thêm về vấn đề này, tôi đã tạo một dự án thử nghiệm tại github.com/Neilski/IdentityBugDemo
Neilski

1
Gặp phải vấn đề này do sử dụng Trình điều khiển.TempData sử dụng Phiên làm cửa hàng sao lưu. Có thể dễ dàng tái tạo việc không thể đăng nhập nếu cookie ASP_NET.SessionId không tồn tại từ yêu cầu trước đó.
kingdango

2
Cuối cùng! Thật là một vấn đề kỳ lạ. Cảm ơn bạn. Đây vẫn là một vấn đề trong hai năm sau khi câu trả lời này được viết.
Spivonious 4/2/2016

43

Bắt đầu với phân tích tuyệt vời của @TomasDolezal, tôi đã xem xét cả nguồn Owin và System.Web.

Vấn đề là System.Web có nguồn thông tin cookie chính và đó không phải là tiêu đề Set-Cookie. Owin chỉ biết về tiêu đề Set-Cookie. Cách giải quyết là đảm bảo rằng mọi cookie được đặt bởi Owin cũng được đặt trongHttpContext.Current.Response.Cookies bộ sưu tập.

Tôi đã tạo một phần mềm trung gian nhỏ ( nguồn , nuget ) thực hiện chính xác điều đó, dự định sẽ được đặt ngay phía trên đăng ký phần mềm trung gian cookie.

app.UseKentorOwinCookieSaver();

app.UseCookieAuthentication(new CookieAuthenticationOptions());

1
Sẽ thử cái này Kể từ sau asp.net Nhận dạng 2.2.0-alpha1, tôi bắt đầu gặp sự cố không chỉ khi đăng nhập mà còn cả việc đăng xuất người dùng (người dùng sẽ không đăng xuất khi đăng xuất nhấp vào | nói chung, trong trường hợp khi tôi mở trang web đôi khi mà không làm gì cả |) .. Và sau khi thiết lập một phiên ngay trước khi người dùng đăng nhập đã giải quyết vấn đề đăng nhập nhưng vấn đề đăng xuất vẫn tồn tại .. Cảm ơn vì nỗ lực của bạn .. Nhân tiện, tôi có nên làm gì khác ngoài việc cài đặt gói?
wooer

Bạn phải kích hoạt nó app.UseKentorCookieMiddlewareSaver();trong Startup.Auth.cs. Nó sẽ xử lý xóa cookie đăng xuất quá.
Anders Abel

Cảm ơn bạn rất nhiều, Anders Abel, cả đăng nhập và đăng xuất đều hoạt động tốt. Nhưng mã trong nhận xét trên cần phải được thay đổi (vì tôi đã làm theo nó :) mà không thành công): app.UseKentorOwinCookieSaver()và có thể bao gồm trong câu trả lời ban đầu của bạn như trong trang GitHub của gói .
wooer

1
Cảm ơn đã nhận thấy tài liệu không chính xác. Nó thực sự đã được sửa trên trang GitHub, nhưng tôi cũng đã cập nhật trong câu trả lời của mình tại đây.
Anders Abel

@AndersAbel Tôi đang cố gắng thêm đăng ký Meetup cho dự án github này: github.com/owin-middleware/OwinOAuthProviders ''. Tôi đã thêm Asana vào một ngày khác và không có vấn đề gì, nhưng vì một số lý do, với Meetup, phương thức chờ đợi xác thực.GetExternalLoginInfoAsync () trong Tài khoản // ExternalLoginCallback sẽ trả về null. Thật không may, gói NuGet của bạn không giải quyết được vấn đề của tôi. Tôi đã tự hỏi nếu bạn có một thời gian để xem xét với tôi vì bạn có thể khắc phục sự cố tốt hơn và đẩy đến dự án của bạn.
Anthony Ruffino

42

Nói tóm lại, trình quản lý cookie .NET sẽ giành chiến thắng trước trình quản lý cookie OWIN và ghi đè lên các cookie được đặt trên lớp OWIN . Cách khắc phục là sử dụng lớp SystemWebCookieManager, được cung cấp dưới dạng một giải pháp trên Dự án Katana tại đây . Bạn cần sử dụng lớp này hoặc một lớp tương tự với nó, điều này sẽ buộc OWIN sử dụng trình quản lý cookie .NET để không xảy ra mâu thuẫn :

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),
            });
    }
}

Khi khởi động ứng dụng của bạn, chỉ cần gán nó khi bạn tạo các phụ thuộc OWIN của mình:

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

Một câu trả lời tương tự đã được cung cấp ở đây nhưng nó không bao gồm tất cả các cơ sở mã cần thiết để giải quyết vấn đề, vì vậy tôi thấy cần phải thêm nó ở đây vì liên kết bên ngoài đến Dự án Katana có thể bị hỏng và điều này cần được ghi chép đầy đủ như một giải pháp ở đây là tốt.


cảm ơn, công việc của tôi, nhưng tôi cũng xóa tất cả các phiên bằng cách gọi bộ điều khiển nàyContext.HttpContext.Session.Remove ALL (); trong chức năng externallogincallback
adnan

Được áp dụng cho ASP.NET Webforms 4.6.1 ? Ứng dụng web của tôi sử dụngASP.NET Webforms, OWIN, ADFS
Kiquenet

@Kiquenet Ứng dụng web của bạn có sử dụng cookie OWIN không? Vậy thì được.
Alexandru

Trong mã Startup.ConfigureAuthchúng tôi có app.UseCookieAuthenticationapp.UseWsFederationAuthenticationcuối cùng app.UseStageMarker
Kiquenet

@Alexandru Bạn có thể xem xét một chỉnh sửa, nhóm của tôi đã gặp lỗi này và nó rất hiếm và ngẫu nhiên, nó đã ẩn chúng tôi thông qua môi trường DEV và UAT. Câu nói này từ câu trả lời của bạn không dành cho chúng tôi: "Trình quản lý cookie .NET sẽ luôn giành chiến thắng." Điều đó sẽ dễ dàng tìm thấy và sửa chữa, nếu các cookie của OWIN luôn bị ghi đè, không có phần mềm trung gian OIDC nào của chúng tôi sẽ làm cho nó biến mất khỏi các máy trạm dev của chúng tôi. Nhưng tính ngẫu nhiên có nghĩa là lỗi đã khiến nó được sản xuất trong 2 ngày trước khi nó tấn công chúng tôi ở quy mô (một nửa sử dụng nội bộ của chúng tôi không thể đăng nhập qua AAD). Có phiền nếu tôi loại bỏ từ "luôn luôn" khỏi câu trả lời của bạn không?
yzorg

17

Đội ngũ Katana đã trả lời về vấn đề mà Tomas Dolezar nêu ra và đăng tài liệu về cách giải quyết :

Cách giải quyết rơi vào hai loại. Một là cấu hình lại System.Web để nó tránh sử dụng bộ sưu tập Feedback.Cookies và ghi đè lên các cookie OWIN. Cách tiếp cận khác là định cấu hình lại các thành phần OWIN bị ảnh hưởng để chúng viết cookie trực tiếp vào bộ sưu tập Feedback.Cookies của System.Web.

  • Đảm bảo phiên được thiết lập trước khi xác thực: Xung đột giữa cookie System.Web và Katana là theo yêu cầu, do đó, ứng dụng có thể thiết lập phiên theo một số yêu cầu trước luồng xác thực. Điều này sẽ dễ thực hiện khi người dùng đến lần đầu tiên, nhưng có thể khó đảm bảo sau này khi cookie phiên hoặc auth hết hạn và / hoặc cần được làm mới.
  • Vô hiệu hóa SessionStateModule - Nếu ứng dụng không dựa vào thông tin phiên, nhưng mô-đun phiên vẫn đang đặt cookie gây ra xung đột ở trên, thì bạn có thể xem xét việc vô hiệu hóa mô-đun trạng thái phiên.
  • Định cấu hình lại CookieAuthenticationMiddleware để ghi trực tiếp vào bộ sưu tập cookie của System.Web.
app.UseCookieAuthentication(new CookieAuthenticationOptions
                                {
                                    // ...
                                    CookieManager = new SystemWebCookieManager()
                                });

Xem triển khai SystemWebCookieManager từ tài liệu (liên kết ở trên)

Thêm thông tin ở đây

Biên tập

Dưới đây là các bước chúng tôi đã thực hiện để giải quyết vấn đề. Cả 1. và 2. cũng giải quyết vấn đề một cách riêng biệt nhưng chúng tôi quyết định áp dụng cả hai chỉ trong trường hợp:

1. Sử dụng SystemWebCookieManager

2. Đặt biến phiên:

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;
}

(lưu ý bên lề: phương thức Khởi tạo ở trên là vị trí hợp lý cho sửa lỗi vì cơ sở.Initialize làm cho Phiên có sẵn. Tuy nhiên, sửa lỗi cũng có thể được áp dụng sau vì trong OpenId trước tiên có một yêu cầu ẩn danh, sau đó chuyển hướng đến nhà cung cấp OpenId và sau đó quay lại đối với ứng dụng. Các sự cố sẽ xảy ra sau khi chuyển hướng quay lại ứng dụng trong khi sửa lỗi đặt biến phiên đã có trong yêu cầu ẩn danh đầu tiên, do đó khắc phục sự cố trước khi bất kỳ chuyển hướng nào quay lại thậm chí xảy ra)

Chỉnh sửa 2

Sao chép-dán từ dự án Katana 2016-05-14:

Thêm điều này:

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

...và điều này:

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),
            });
    }
}

Tôi thấy câu trả lời này đơn giản hơn nhiều và dễ dàng khắc phục vấn đề hơn. Cảm ơn, - Có lẽ tôi đã nói quá đột ngột. Điều này đã không giải quyết vấn đề của tôi.
JCS

@JCS Bao gồm các bước chúng tôi đã thực hiện để giải quyết vấn đề. Bạn đã tìm hiểu xem vấn đề của bạn có liên quan?
thomius

Tôi đang sử dụng Web Api 2 + phần mềm trung gian Owin + redis cache để quản lý phiên để xác thực. Tôi đã thử sử dụng SystemWebCookieManager và nó không giải quyết được vấn đề tôi gặp phải khi các cookie xác thực không được đặt. Sử dụng "UseKentorOwinCookieSaver" đã giải quyết vấn đề đó nhưng tôi không quá thích một sự phụ thuộc bên ngoài ...
JCS

Xóa phiên làm việc cho tôi. Không cần phụ thuộc bên ngoài. Đặt điều này ControllerContext.HttpContext.Session.RemoveAll();trong ExternalLogin()hành động của bạn , trước khi gọi ChallengeResult(). Tôi không biết liệu đó có phải là giải pháp tốt nhất hay không, nhưng nó đơn giản nhất.
Alisson

1
@CHitaxis chắc chắn, chỉ cần lưu ý ?.(toán tử có điều kiện null) chỉ hoạt động trong C # 6.
Alisson

5

Câu trả lời đã được cung cấp, nhưng trong owin 3.1.0, có một lớp SystemWebChunkingCookieManager có thể được sử dụng.

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.

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

Đây có phải vẫn là một vấn đề trong 3.1.0?
cyberconte

1
Có, nó vẫn là một vấn đề trong 3.1.0 đối với tôi và cần trình quản lý cookie này, vì cái mặc định vẫn là ChunkingCookieManager.
jonmeyer

Có thể dùng ở đâu? và làm thế nào?
Simon_Weaver

@jonmeyer cảm ơn. Tôi nghĩ hôm qua tôi đã bỏ lỡ sự khác biệt giữa SystemCCM và CCM vì vậy tôi chắc chắn sẽ kiểm tra điều này
Simon_Weaver

ngay cả sau khi thêm dòng trên nó không hoạt động cho tôi. tôi đang sử dụng phiên bản 3.1.0. Chủ yếu tôi có thể đăng nhập lần đầu nhưng sau khi đăng xuất thì không cho phép tôi đăng nhập.
Mitin Dixit

3

Nếu bạn đang tự đặt cookie trong phần mềm trung gian OWIN, thì việc sử dụng OnSendingHeadersdường như sẽ giải quyết được vấn đề.

Ví dụ: sử dụng mã bên dưới owinResponseCookie2sẽ được đặt, mặc dù owinResponseCookie1không phải là:

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

Tôi đã phải đối mặt với Vấn đề tương tự với Visual Studio 2017.net MVC 5.2.4 , Cập nhật Nuget Microsoft.Owin.Security.Google thành phiên bản mới nhất hiện đang là 4.0.1 hoạt động với tôi! Hy vọng điều này sẽ giúp ai đó!


1
Lưu thịt xông khói của tôi vào cái này! Đã xảy ra sự cố với Android Chrome, đặc biệt mất xác thực ngẫu nhiên. Không có gì khác trong chủ đề này làm việc. Tôi đang sử dụng VS2019 và ASP MVC 5.
zfrank

2

Giải pháp mã một dòng nhanh nhất:

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

Chỉ cần thêm dòng này trước khi phương thức CreatIdentity:

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

1
Bạn đặt mã này ở HttpContext.Current.Session["RunSession"] = "1";đâu? trong Globa.asax Session_Start ?
Kiquenet

1
Trên thực tế, đây là giải pháp đơn giản và nhanh nhất hiện có và cho đến khi giải pháp cho vấn đề đó sẽ không được đưa vào Khung (đã thông báo rằng nó sẽ) - Ví dụ, tôi thích một lớp lót, thay vì một lớp phụ thuộc + . Giải pháp này được IMHO đánh giá thấp.
Der Zinger

Tôi đã thêm nó vào AuthManager của mình ở đầu phương thức IssueAuthToken
Alexander Trofimov

1

Tôi có cùng một triệu chứng về tiêu đề Set-Cookie không được gửi nhưng không có câu trả lời nào trong số này giúp tôi. Mọi thứ đều hoạt động trên máy cục bộ của tôi nhưng khi được triển khai để sản xuất các tiêu đề cookie tập hợp sẽ không bao giờ được đặt.

Hóa ra đó là sự kết hợp của việc sử dụng một tùy chỉnh CookieAuthenticationMiddlewarevới WebApi cùng với hỗ trợ nén WebApi

May mắn thay, tôi đã sử dụng ELMAH trong dự án của mình, điều này cho phép tôi ngoại lệ được ghi lại:

System.Web.HttpException Server không thể nối thêm tiêu đề sau khi tiêu đề HTTP được gửi.

Điều này dẫn tôi đến vấn đề GitHub này

Về cơ bản, nếu bạn có một thiết lập kỳ lạ như của tôi, bạn sẽ muốn tắt tính năng nén cho các bộ điều khiển / phương thức WebApi để đặt cookie hoặc thử OwinServerCompressionHandler.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.