Truy cập phiên bằng API Web ASP.NET


268

Tôi nhận thấy phiên và REST không thực sự đi đôi với nhau nhưng không thể truy cập trạng thái phiên bằng API Web mới? HttpContext.Current.Sessionluôn luôn là null.


4
[SessionState(SessionStateBehavior.Required)]trên ApiControllerlừa đảo (hoặc .ReadOnlykhi thích hợp).
Roman Starkov

@RomanStarkov Không thể làm việc này. Bạn đã sử dụng môi trường nào? Lõi .NET?
Bondolin

@Bondolin không, đây không phải là Core.
Roman Starkov

@RomanStarkov MVC thì sao? Tôi gặp khó khăn khi tìm nó.
Bondolin

@Bondolin SessionStateAttribution và có, MVC.
Roman Starkov

Câu trả lời:


336

MVC

Đối với một dự án MVC, hãy thực hiện các thay đổi sau (WebForms và Dot Net Core trả lời bên dưới):

WebApiConfig.cs

public static class WebApiConfig
{
    public static string UrlPrefix         { get { return "api"; } }
    public static string UrlPrefixRelative { get { return "~/api"; } }

    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

Toàn cầu.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    ...

    protected void Application_PostAuthorizeRequest()
    {
        if (IsWebApiRequest())
        {
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

    private bool IsWebApiRequest()
    {
        return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
    }

}

Giải pháp này có phần thưởng bổ sung mà chúng tôi có thể tìm nạp URL cơ sở trong javascript để thực hiện các cuộc gọi AJAX:

_Layout.cshtml

<body>
    @RenderBody()

    <script type="text/javascript">
        var apiBaseUrl = '@Url.Content(ProjectNameSpace.WebApiConfig.UrlPrefixRelative)';
    </script>

    @RenderSection("scripts", required: false) 

và sau đó trong các tệp / mã Javascript của chúng tôi, chúng tôi có thể thực hiện các cuộc gọi webapi có thể truy cập phiên:

$.getJSON(apiBaseUrl + '/MyApi')
   .done(function (data) {
       alert('session data received: ' + data.whatever);
   })
);

WebForms

Thực hiện như trên nhưng thay đổi hàm WebApiConfig.Register để lấy RouteCollection thay thế:

public static void Register(RouteCollection routes)
{
    routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

Và sau đó gọi như sau trong Application_Start:

WebApiConfig.Register(RouteTable.Routes);

Lõi lưới

Thêm gói Microsoft.AspNetCore.Session NuGet và sau đó thực hiện các thay đổi mã sau:

Startup.cs

Gọi AddDistributedMemoryCacheAddSession phương pháp trên các dịch vụ đối tượng trong ConfigureServices chức năng:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    ...

    services.AddDistributedMemoryCache();
    services.AddSession();

và trong chức năng Cấu hình, thêm một cuộc gọi đến UseSession :

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
    app.UseSession();
    app.UseMvc();

SessionControll.cs

Trong bộ điều khiển của bạn, thêm một câu lệnh sử dụng ở trên cùng:

using Microsoft.AspNetCore.Http;

và sau đó sử dụng đối tượng HttpContext.Session trong mã của bạn như vậy:

    [HttpGet("set/{data}")]
    public IActionResult setsession(string data)
    {
        HttpContext.Session.SetString("keyname", data);
        return Ok("session data set");
    }

    [HttpGet("get")]
    public IActionResult getsessiondata()
    {
        var sessionData = HttpContext.Session.GetString("keyname");
        return Ok(sessionData);
    }

bây giờ bạn có thể đánh:

http://localhost:1234/api/session/set/thisissomedata

và sau đó truy cập URL này sẽ kéo nó ra:

http://localhost:1234/api/session/get

Nhiều thông tin hơn về việc truy cập dữ liệu phiên trong lõi mạng chấm tại đây: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state

Mối quan tâm về hiệu suất

Đọc câu trả lời của Simon Weaver dưới đây về hiệu suất. Nếu bạn đang truy cập dữ liệu phiên bên trong dự án WebApi, nó có thể có hậu quả hiệu suất rất nghiêm trọng - Tôi đã thấy ASP.NET thực thi độ trễ 200ms cho các yêu cầu đồng thời. Điều này có thể cộng lại và trở thành thảm họa nếu bạn có nhiều yêu cầu đồng thời.


Quan ngại về an ninh

Đảm bảo rằng bạn đang khóa tài nguyên trên mỗi người dùng - một người dùng được xác thực sẽ không thể truy xuất dữ liệu từ WebApi mà họ không có quyền truy cập.

Đọc bài viết của Microsoft về Xác thực và Ủy quyền trong API Web ASP.NET - https://www.asp.net/web-api/overview/security/authentication-and-masterization-in-aspnet-web-api

Đọc bài viết của Microsoft về việc tránh các cuộc tấn công hack Yêu cầu chéo trang web. (Tóm lại, hãy kiểm tra phương pháp AntiForgery.Validate) - https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks


7
Hoàn hảo. Đơn giản và nó hoạt động. Đối với phi MVC, chỉ cần thêm Application_PostAuthorizeRequest () vào Global.ascx.cs.
mhenry1384

1
Cảm ơn @JCallico, tôi đoán rằng hầu hết mọi người đều truy cập trang ASP.NET trước tiên để tạo phiên.
Rocklan

3
Tôi cần sửa đổi IsWebApiRequest () để trả về true khi đường dẫn bắt đầu với WebApiConfig.UrlPrefix, cũng như WebApiConfig.UrlPrefixRelative. Ngoài ra, hoạt động như mong đợi.
gb2d

7
Một điều cần đề cập liên quan đến sửa chữa này. khi đặt SessionStateBehavior thành Bắt buộc, bạn đang tắc nghẽn webapi, vì tất cả các yêu cầu của bạn sẽ chạy được đồng bộ hóa do khóa trên đối tượng phiên. Thay vào đó, bạn có thể chạy nó dưới dạng SessionStateBehavior.Readonly. Bằng cách này, nó sẽ không tạo khóa trên đối tượng phiên.
Michael Kire Hansen

2
Hãy cẩn thận khi đặt hành vi trạng thái phiên thành "Bắt buộc". Các yêu cầu có quyền ghi sẽ khóa phiên và ngăn không cho nhiều HTTPApplecting được sinh ra trên mỗi máy khách. Bạn nên đặt trạng thái phiên ở mức phù hợp cho từng tuyến. Vui lòng tham khảo câu trả lời của tôi ở đây: stackoverflow.com/a/34727708/1412787
Axel Wilczek

66

Bạn có thể truy cập trạng thái phiên bằng cách sử dụng RouteHandler tùy chỉnh.

// In global.asax
public class MvcApp : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        var route = routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        route.RouteHandler = new MyHttpControllerRouteHandler();
    }
}

// Create two new classes
public class MyHttpControllerHandler
    : HttpControllerHandler, IRequiresSessionState
{
    public MyHttpControllerHandler(RouteData routeData) : base(routeData)
    { }
}
public class MyHttpControllerRouteHandler : HttpControllerRouteHandler
{
    protected override IHttpHandler GetHttpHandler(
        RequestContext requestContext)
    {
        return new MyHttpControllerHandler(requestContext.RouteData);
    }
}

// Now Session is visible in your Web API
public class ValuesController : ApiController
{
    public string Get(string input)
    {
        var session = HttpContext.Current.Session;
        if (session != null)
        {
            if (session["Time"] == null)
                session["Time"] = DateTime.Now;
            return "Session Time: " + session["Time"] + input;
        }
        return "Session is not availabe" + input;
    }
}

Tìm thấy ở đây: http://techhasnoboundary.blogspot.com/2012/03/mvc-4-web-api-access-session.html


14
Cập nhật: nếu các hàm API của bạn đọc từ phiên và không sửa đổi phiên, có thể nên sử dụng IReadOnlySessionState thay vì IRequiresSessionState. Điều này đảm bảo phiên không bị khóa trong quá trình xử lý chức năng API.
warrickh

6
không hoạt động với tôi trong MVC 4 - route.RouteHandler thậm chí không phải là một tài sản đối với tôi. @LachlanB dường như có những gì làm việc cho tôi.
bkwdesign

3
Cảm ơn @bkwdesign đã chỉ ra giải pháp MVC. Câu trả lời này chỉ liên quan đến API Web.
warrickh

2
Điều này dường như không hỗ trợ các thuộc tính tuyến. Suy nghĩ?
Tim S

Như bkwdesign đã chỉ ra, điều này không còn được hỗ trợ. Tuy nhiên, có một cách để xác định hành vi trạng thái phiên trên mỗi tuyến bằng DataTokens: stackoverflow.com/a/34727708/1412787
Axel Wilczek

46

Tại sao phải tránh sử dụng Phiên trong WebAPI?

Hiệu suất, hiệu suất, hiệu suất!

Có một lý do rất hay và thường bị bỏ qua tại sao bạn không nên sử dụng Phiên trong WebAPI.

Cách ASP.NET hoạt động khi Phiên được sử dụng là để tuần tự hóa tất cả các yêu cầu nhận được từ một khách hàng . Bây giờ tôi không nói về tuần tự hóa đối tượng - nhưng chạy chúng theo thứ tự nhận được và chờ đợi từng cái hoàn thành trước khi chạy tiếp theo. Điều này là để tránh các điều kiện luồng / cuộc đua khó chịu nếu hai yêu cầu mỗi lần thử truy cập Phiên.

Yêu cầu đồng thời và trạng thái phiên

Quyền truy cập vào trạng thái phiên ASP.NET là độc quyền cho mỗi phiên, có nghĩa là nếu hai người dùng khác nhau thực hiện các yêu cầu đồng thời, quyền truy cập vào từng phiên riêng biệt được cấp đồng thời. Tuy nhiên, nếu hai yêu cầu đồng thời được thực hiện cho cùng một phiên (bằng cách sử dụng cùng một giá trị SessionID), yêu cầu đầu tiên sẽ có quyền truy cập độc quyền vào thông tin phiên. Yêu cầu thứ hai chỉ thực hiện sau khi yêu cầu đầu tiên kết thúc.(Phiên thứ hai cũng có thể có quyền truy cập nếu khóa độc quyền trên thông tin được giải phóng vì yêu cầu đầu tiên vượt quá thời gian khóa.) Nếu giá trị EnableSessionState trong chỉ thị @ Trang được đặt thành ReadOnly, yêu cầu chỉ đọc thông tin phiên không dẫn đến khóa độc quyền trên dữ liệu phiên. Tuy nhiên, các yêu cầu chỉ đọc cho dữ liệu phiên có thể vẫn phải chờ khóa được đặt bởi yêu cầu đọc ghi để dữ liệu phiên xóa.

Vậy điều này có ý nghĩa gì với API Web? Nếu bạn có một ứng dụng chạy nhiều yêu cầu AJAX thì chỉ có MỘT là có thể chạy cùng một lúc. Nếu bạn có một yêu cầu chậm hơn thì nó sẽ chặn tất cả những người khác từ khách hàng đó cho đến khi hoàn thành. Trong một số ứng dụng, điều này có thể dẫn đến hiệu suất chậm chạp đáng chú ý.

Vì vậy, có lẽ bạn nên sử dụng bộ điều khiển MVC nếu bạn thực sự cần thứ gì đó từ phiên người dùng và tránh hình phạt hiệu năng không cần thiết khi kích hoạt nó cho WebApi.

Bạn có thể dễ dàng tự kiểm tra điều này bằng cách chỉ cần đưa Thread.Sleep(5000)vào một phương thức WebAPI và kích hoạt Phiên. Chạy 5 yêu cầu đến nó và họ sẽ mất tổng cộng 25 giây để hoàn thành. Nếu không có Phiên, họ sẽ mất tổng cộng chỉ hơn 5 giây.

(Lý do tương tự này áp dụng cho SignalR).


18
Bạn có thể khắc phục điều này bằng cách sử dụng [SessionState (SessionStateBehavior.ReadOnly)] nếu phương thức của bạn chỉ đọc từ phiên.
Rocklan

21

Vâng, bạn đúng, REST là không quốc tịch. Nếu bạn sử dụng một phiên, quá trình xử lý sẽ trở nên trạng thái, các yêu cầu tiếp theo sẽ có thể sử dụng trạng thái (từ một phiên).

Để phiên được bù nước, bạn sẽ cần cung cấp khóa để liên kết trạng thái. Trong một ứng dụng asp.net bình thường, khóa đó được cung cấp bằng cách sử dụng cookie (phiên cookie) hoặc tham số url (phiên không nấu ăn).

Nếu bạn cần một phiên quên phần còn lại, các phiên không liên quan trong các thiết kế dựa trên REST. Nếu bạn cần một phiên để xác thực thì hãy sử dụng mã thông báo hoặc ủy quyền theo địa chỉ IP.


10
Tôi không chắc về điều này. Trong các ví dụ của Microsoft, họ hiển thị bằng thuộc tính Authorize. Tôi đã thử điều đó và nó hoạt động với Xác thực dựa trên mẫu. API Web nhận biết trạng thái xác thực đang được thông qua trong cookie xác thực mặc định.
Đánh dấu

4
Đây là mẫu mà tôi đang đề cập đến, code.msdn.microsoft.com/ASPNET-Web-API-JavaScript-d0d64dd7 . Nó sử dụng API Web dựa trên REST mới thực hiện Xác thực mẫu.
Đánh dấu

4
Tôi đã sử dụng thuộc tính [Ủy quyền] thành công mà không cần trạng thái phiên. Tôi chỉ viết một trình xử lý tin nhắn xác thực để đặt danh tính.
Antony Scott

57
Đánh dấu bạn vì bạn không đưa ra câu trả lời cho vấn đề của anh ấy và hơn thế nữa, Api Web là một khung không đồng bộ hoạt động tuyệt vời với ứng dụng web nặng ajax. Không ai nói rằng bạn phải tôn trọng tất cả những người thuê thiết kế RESTful để đạt được lợi ích từ việc sử dụng khung API Web.
Brian Ogden

3
@Điểm. có quyền thông báo rằng API Web không được phép biết về trạng thái phiên. Câu trả lời phủ định vẫn là một câu trả lời. Lên phiếu.
Antoine Meltzheim

20

Đánh dấu, nếu bạn kiểm tra ví dụ MVC nerddinner thì logic khá giống nhau.

Bạn chỉ cần truy xuất cookie và đặt nó trong phiên hiện tại.

Toàn cầu.asax.cs

public override void Init()
{
    this.AuthenticateRequest += new EventHandler(WebApiApplication_AuthenticateRequest);
    base.Init();
}

void WebApiApplication_AuthenticateRequest(object sender, EventArgs e)
{
    HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);

    SampleIdentity id = new SampleIdentity(ticket);
    GenericPrincipal prin = new GenericPrincipal(id, null); 

    HttpContext.Current.User = prin;
}

enter code here

Bạn sẽ phải xác định lớp "SampleIdentity" mà bạn có thể mượn từ dự án nerddinner .


Lớp nhận dạng nằm trong NerdDinner_2.0 \ NerdDinner \ Model \ NerdIdentity.cs.
mhenry1384

Điều này không làm việc cho tôi (trong .NET 4). Tôi không bao giờ có cookie đó. Có phải nó chỉ hoạt động nếu bạn bật FormsAuthentication?
mhenry1384

cookie thực sự được tạo sau khi bạn xác thực thông qua biểu mẫu đăng nhập. Bạn cũng có thể tùy chỉnh cách thức / thời điểm nó được tạo, xem stackoverflow.com/questions/7217105 Nhưng bạn vẫn cần người dùng xác thực hiệu quả với máy chủ web
JSancho

Câu hỏi yêu cầu cho HTTPContext.Cản.Session và câu trả lời này không giải thích rõ ràng những gì cần phải làm. Xem câu trả lời @LachlanB.
JCallico

14

Để khắc phục sự cố:

protected void Application_PostAuthorizeRequest()
{
    System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
}

trong Global.asax.cs


4
Cảnh báo! Điều này sẽ kích hoạt phiên cho TẤT CẢ các yêu cầu. Điều này thực sự có thể ảnh hưởng đến hiệu suất nếu ứng dụng của bạn đang sử dụng tài nguyên nhúng.
cgatian

@cgatian giải pháp thay thế nào cố định ?
Kiquenet

Tôi nghĩ cách tiếp cận tốt nhất là những gì @Treyphor gợi ý. Đừng kích hoạt nó cho tất cả các yêu cầu. Chỉ các tuyến đường có "/ api" hoặc một cái gì đó trong URL. Ngoài ra, nếu có thể, hãy đặt trạng thái phiên chỉ đọc cho bộ điều khiển API của bạn.
cgatian

10

Cái cuối cùng không hoạt động bây giờ, hãy lấy cái này, nó làm việc cho tôi.

trong WebApiConfig.cs tại App_Start

    public static string _WebApiExecutionPath = "api";

    public static void Register(HttpConfiguration config)
    {
        var basicRouteTemplate = string.Format("{0}/{1}", _WebApiExecutionPath, "{controller}");

        // Controller Only
        // To handle routes like `/api/VTRouting`
        config.Routes.MapHttpRoute(
            name: "ControllerOnly",
            routeTemplate: basicRouteTemplate//"{0}/{controller}"
        );

        // Controller with ID
        // To handle routes like `/api/VTRouting/1`
        config.Routes.MapHttpRoute(
            name: "ControllerAndId",
            routeTemplate: string.Format ("{0}/{1}", basicRouteTemplate, "{id}"),
            defaults: null,
            constraints: new { id = @"^\d+$" } // Only integers 
        );

Toàn cầu

protected void Application_PostAuthorizeRequest()
{
  if (IsWebApiRequest())
  {
    HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
  }
}

private static bool IsWebApiRequest()
{
  return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(_WebApiExecutionPath);
}

thứ tư tại đây: http://forums.asp.net/t/1773026.aspx/1


Đây là giải pháp đơn giản nhất nhưng có một vài lỗi trong mã để nó không thực sự hoạt động. Tôi đã đăng một giải pháp khác dựa trên giải pháp này, vui lòng chỉnh sửa giải pháp của bạn để phù hợp với giải pháp của tôi.
Rocklan

Sửa lỗi nhẹ trên dòng _WebApiExecutPath cần đọc chuỗi tĩnh công khai _WebApiExecutPath = "~ / api";
stephen ebichondo

8

Theo dõi câu trả lời của LachlanB, nếu ApiControll của bạn không ngồi trong một thư mục cụ thể (như / api), bạn có thể kiểm tra yêu cầu bằng RouteTable.Routes.GetRouteData, ví dụ:

protected void Application_PostAuthorizeRequest()
    {
        // WebApi SessionState
        var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
        if (routeData != null && routeData.RouteHandler is HttpControllerRouteHandler)
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
    }

8

Tôi gặp vấn đề tương tự trong asp.net mvc, tôi đã khắc phục bằng cách đưa phương thức này vào bộ điều khiển api cơ sở mà tất cả các bộ điều khiển api của tôi thừa hưởng từ:

    /// <summary>
    /// Get the session from HttpContext.Current, if that is null try to get it from the Request properties.
    /// </summary>
    /// <returns></returns>
    protected HttpContextWrapper GetHttpContextWrapper()
    {
      HttpContextWrapper httpContextWrapper = null;
      if (HttpContext.Current != null)
      {
        httpContextWrapper = new HttpContextWrapper(HttpContext.Current);
      }
      else if (Request.Properties.ContainsKey("MS_HttpContext"))
      {
        httpContextWrapper = (HttpContextWrapper)Request.Properties["MS_HttpContext"];
      }
      return httpContextWrapper;
    }

Sau đó, trong cuộc gọi api của bạn mà bạn muốn truy cập vào phiên bạn vừa làm:

HttpContextWrapper httpContextWrapper = GetHttpContextWrapper();
var someVariableFromSession = httpContextWrapper.Session["SomeSessionValue"];

Tôi cũng có tệp này trong tệp Global.asax.cs của mình như những người khác đã đăng, không chắc bạn có còn cần nó bằng phương pháp trên không, nhưng đây chỉ là trong trường hợp:

/// <summary>
/// The following method makes Session available.
/// </summary>
protected void Application_PostAuthorizeRequest()
{
  if (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith("~/api"))
  {
    HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
  }
}

Bạn cũng có thể tạo một thuộc tính bộ lọc tùy chỉnh mà bạn có thể dính vào các cuộc gọi api mà bạn cần phiên, sau đó bạn có thể sử dụng phiên trong cuộc gọi api của mình như bạn thường làm thông qua HttpContext.Cản.Session ["someValue"]:

  /// <summary>
  /// Filter that gets session context from request if HttpContext.Current is null.
  /// </summary>
  public class RequireSessionAttribute : ActionFilterAttribute
  {
    /// <summary>
    /// Runs before action
    /// </summary>
    /// <param name="actionContext"></param>
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
      if (HttpContext.Current == null)
      {
        if (actionContext.Request.Properties.ContainsKey("MS_HttpContext"))
        {
          HttpContext.Current = ((HttpContextWrapper)actionContext.Request.Properties["MS_HttpContext"]).ApplicationInstance.Context;
        }
      }
    }
  }

Hi vọng điêu nay co ich.


6

Tôi đã làm theo cách tiếp cận @LachlanB và thực sự phiên đã có sẵn khi cookie phiên có mặt theo yêu cầu. Phần còn thiếu là làm thế nào cookie phiên được gửi cho khách hàng lần đầu tiên?

Tôi đã tạo một HTTPModule, nó không chỉ cho phép tính khả dụng của httpSessionState mà còn gửi cookie cho khách hàng khi một phiên mới được tạo.

public class WebApiSessionModule : IHttpModule
{
    private static readonly string SessionStateCookieName = "ASP.NET_SessionId";

    public void Init(HttpApplication context)
    {
        context.PostAuthorizeRequest += this.OnPostAuthorizeRequest;
        context.PostRequestHandlerExecute += this.PostRequestHandlerExecute;
    }

    public void Dispose()
    {
    }

    protected virtual void OnPostAuthorizeRequest(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;

        if (this.IsWebApiRequest(context))
        {
            context.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

    protected virtual void PostRequestHandlerExecute(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;

        if (this.IsWebApiRequest(context))
        {
            this.AddSessionCookieToResponseIfNeeded(context);
        }
    }

    protected virtual void AddSessionCookieToResponseIfNeeded(HttpContext context)
    {
        HttpSessionState session = context.Session;

        if (session == null)
        {
            // session not available
            return;
        }

        if (!session.IsNewSession)
        {
            // it's safe to assume that the cookie was
            // received as part of the request so there is
            // no need to set it
            return;
        }

        string cookieName = GetSessionCookieName();
        HttpCookie cookie = context.Response.Cookies[cookieName];
        if (cookie == null || cookie.Value != session.SessionID)
        {
            context.Response.Cookies.Remove(cookieName);
            context.Response.Cookies.Add(new HttpCookie(cookieName, session.SessionID));
        }
    }

    protected virtual string GetSessionCookieName()
    {
        var sessionStateSection = (SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState");

        return sessionStateSection != null && !string.IsNullOrWhiteSpace(sessionStateSection.CookieName) ? sessionStateSection.CookieName : SessionStateCookieName;
    }

    protected virtual bool IsWebApiRequest(HttpContext context)
    {
        string requestPath = context.Request.AppRelativeCurrentExecutionFilePath;

        if (requestPath == null)
        {
            return false;
        }

        return requestPath.StartsWith(WebApiConfig.UrlPrefixRelative, StringComparison.InvariantCultureIgnoreCase);
    }
}

Điều này làm việc tuyệt vời. Điều này giữ cho phiên giống nhau giữa các yêu cầu miễn là nó không hết hạn. Không chắc chắn liệu tôi có sử dụng nó trong prod chưa cho đến khi tôi tìm ra một cách tốt để chuyển trạng thái phiên giữa yêu cầu và chỉ đọc để dừng chặn yêu cầu, nhưng điều này đã cho tôi con đường bắt đầu mà tôi mong muốn. Cảm ơn bạn!
Derreck Dean

3

một điều cần đề cập đến câu trả lời của @LachlanB.

protected void Application_PostAuthorizeRequest()
    {
        if (IsWebApiRequest())
        {
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

Nếu bạn bỏ qua dòng if (IsWebApiRequest())

Toàn bộ trang web sẽ có vấn đề tải trang chậm nếu trang web của bạn được trộn với các trang mẫu web.


0

Có, phiên không đi đôi với Rest API và chúng ta cũng nên tránh thực hành này. Nhưng theo yêu cầu, chúng tôi cần duy trì phiên bằng cách nào đó để trong mọi máy chủ khách hàng yêu cầu có thể trao đổi hoặc duy trì trạng thái hoặc dữ liệu. Vì vậy, cách tốt nhất để đạt được điều này mà không phá vỡ các giao thức REST là giao tiếp thông qua mã thông báo như JWT.

https://jwt.io/


-4

Quay trở lại vấn đề cơ bản tại sao không giữ nó đơn giản và lưu trữ giá trị Phiên trong một giá trị html ẩn để chuyển đến API của bạn?

Bộ điều khiển

public ActionResult Index()
        {

            Session["Blah"] = 609;

            YourObject yourObject = new YourObject();
            yourObject.SessionValue = int.Parse(Session["Blah"].ToString());

            return View(yourObject);
        }

cshtml

@model YourObject

@{
    var sessionValue = Model.SessionValue;
}

<input type="hidden" value="@sessionValue" id="hBlah" />

Javascript

$ (tài liệu). yet (function () {

    var sessionValue = $('#hBlah').val();

    alert(sessionValue);

    /* Now call your API with the session variable */}

}


1
Nếu ứng dụng sử dụng cả MVC và WebAPI? Ngoài ra, sẽ hợp lý hơn khi một số thứ được lưu trữ ở phía máy chủ, ví dụ: mã thông báo bảo mật Sharepoint. Thay vì triển khai một trình bao bọc đặc biệt để lưu trữ mã thông báo như bộ chứa các đốm màu xanh, đôi khi là phiên tái sử dụng hợp lý cho loại dữ liệu này. Bối cảnh bảo mật Sharepoint khi được triển khai trong mẫu ứng dụng, sử dụng phiên để lưu trữ các bối cảnh bảo mật này và chỉ các phần dữ liệu nhỏ được truyền (thẻ phiên) thay vì vài kilobyte dữ liệu. Thật tuyệt vời nếu bối cảnh này sẽ nhỏ hơn ...
Konstantin Isaev
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.