programing

ASP를 사용하여 세션에 액세스합니다.NET 웹 API

javamemo 2023. 5. 10. 20:11
반응형

ASP를 사용하여 세션에 액세스합니다.NET 웹 API

세션과 REST가 정확히 함께 진행되지 않는다는 것을 알고 있습니다만, 새로운 웹 API를 사용하여 세션 상태에 액세스할 수는 없습니까? HttpContext.Current.Session항상 null입니다.

MVC

MVC 프로젝트의 경우 다음과 같이 변경합니다(아래의 WebForms 및 DotNet Core 답변).

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

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

}

이 솔루션에는 AJAX 호출을 위한 기본 URL을 Javascript로 가져올 수 있는 추가 보너스가 있습니다.

_Layout.cshtml

<body>
    @RenderBody()

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

    @RenderSection("scripts", required: false) 

그런 다음 Javascript 파일/코드 내에서 세션에 액세스할 수 있는 webapi 호출을 수행할 수 있습니다.

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

웹 양식

위의 작업을 수행하지만 WebApiConfig를 변경합니다.대신 RouteCollection을 사용하도록 함수를 등록합니다.

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

그런 다음 Application_Start에서 다음을 호출합니다.

WebApiConfig.Register(RouteTable.Routes);

닷넷 코어

Microsoft를 추가합니다.AsNetCore.세션 NuGet 패키지를 선택한 후 다음 코드를 변경합니다.

Startup.cs

ConfigureServices 함수 내의 services 개체에서 AddDistributedMemoryCacheAddSession 메서드를 호출합니다.

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

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

Configure(구성) 기능에서 UseSession(사용 세션)에 대한 호출을 추가합니다.

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

SessionController.cs

컨트롤러의 맨 위에 다음 명령문을 추가합니다.

using Microsoft.AspNetCore.Http;

그런 다음 HttpContext를 사용합니다.코드 내의 세션 개체는 다음과 같습니다.

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

이제 다음을 칠 수 있습니다.

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

그런 다음 이 URL로 이동하면 해당 URL이 표시됩니다.

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

닷넷 코어 내 세션 데이터 액세스에 대한 자세한 내용은 여기를 참조하십시오. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state

성능 문제

성과와 관련하여 아래의 사이먼 위버의 답변을 읽어보십시오.WebApi 프로젝트 내에서 세션 데이터에 액세스하는 경우 매우 심각한 성능 결과를 초래할 수 있습니다. ASP를 본 적이 있습니다.NET은 동시 요청에 대해 200ms 지연을 적용합니다.동시에 많은 요청이 있을 경우 이 문제가 추가되고 심각한 문제가 될 수 있습니다.


보안 문제

사용자별로 리소스를 잠그고 있는지 확인합니다. 인증된 사용자는 액세스할 수 없는 웹 API에서 데이터를 검색할 수 없습니다.

ASP의 인증 및 권한 부여에 대한 Microsoft의 기사를 읽어 보십시오.NET 웹 API - https://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

사이트 간 요청 위조 해킹 공격 방지에 대한 Microsoft의 기사를 읽으십시오. (간단히 말해, AntiForgement를 확인하십시오.)방법 확인) - https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks

사용자 지정 RouteHandler를 사용하여 세션 상태에 액세스할 수 있습니다.

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

다음 위치: http://techhasnoboundary.blogspot.com/2012/03/mvc-4-web-api-access-session.html

WebAPI에서 세션을 사용하지 않는 이유는 무엇입니까?

성능, 성능, 성능!

WebAPI에서 세션을 사용하면 안 되는 매우 좋은 이유가 있으며 종종 간과됩니다.

ASP 방식.세션이 사용 중인 경우 NET 네트워크는 단일 클라이언트에서 수신한 모든 요청을 직렬화하는 것입니다.이제 저는 객체 직렬화에 대해 이야기하는 것이 아니라 수신된 순서대로 실행하고 다음을 실행하기 전에 각각이 완료될 때까지 기다립니다.이는 각각 두 개의 요청이 동시에 세션에 액세스하려고 할 경우 좋지 않은 스레드/레이스 상태를 방지하기 위한 것입니다.

동시 요청 및 세션 상태

ASP에 대한 액세스 권한.NET 세션 상태는 세션별로 배타적입니다. 즉, 서로 다른 두 사용자가 동시에 요청을 하면 각 개별 세션에 대한 액세스가 동시에 허용됩니다.그러나 동일한 세션에 대해개의 동시 요청이 이루어진 경우(동일한 세션 사용ID 값), 첫 번째 요청은 세션 정보에 대한 단독 액세스 권한을 가집니다. 두 번째 요청은 첫 번째 요청이 완료된 후에만 실행됩니다. (첫 번째 요청이 잠금 제한 시간을 초과하여 정보에 대한 배타적 잠금이 해제된 경우에도 두 번째 세션에 액세스할 수 있습니다.)@Page 디렉티브의 EnableSessionState 값이 ReadOnly로 설정되어 있으면 읽기 전용 세션 정보에 대한 요청으로 인해 세션 데이터가 배타적으로 잠기지 않습니다.그러나 세션 데이터에 대한 읽기 전용 요청은 세션 데이터를 지우려면 읽기-쓰기 요청에 의해 설정된 잠금을 기다려야 할 수 있습니다.

그렇다면 이것은 웹 API에 어떤 의미가 있을까요?애플리케이션에서 많은 AJAX 요청을 실행하는 경우 한 번에 하나만 실행할 수 있습니다.요청 속도가 느린 경우 클라이언트가 완료될 때까지 클라이언트의 다른 모든 요청을 차단합니다.일부 애플리케이션에서는 성능이 매우 눈에 띄게 저하될 수 있습니다.

따라서 사용자 세션에서 무언가가 꼭 필요한 경우 MVC 컨트롤러를 사용해야 하며 WebApi에 대해 MVC 컨트롤러를 활성화함으로써 발생하는 불필요한 성능 저하를 방지해야 합니다.

당신은 그것을 넣기만 하면 이것을 당신 스스로 쉽게 테스트할 수 있습니다.Thread.Sleep(5000)세션을 활성화할 수 있습니다.5개의 요청을 실행하면 완료하는 데 총 25초가 소요됩니다.세션을 사용하지 않으면 총 5초가 조금 넘게 걸립니다.

(이와 같은 추론이 신호 R에도 적용됩니다.)

당신 말이 맞아요, REST는 무국적입니다.세션을 사용하면 처리가 상태 저장이 되고 이후 요청은 세션의 상태를 사용할 수 있습니다.

세션을 다시 활성화하려면 상태를 연결하는 키를 제공해야 합니다.일반적인 asp.net 응용 프로그램에서 해당 키는 쿠키(cookie-session) 또는 url 매개 변수(cookie 없는 세션)를 사용하여 제공됩니다.

세션 forget rest가 필요한 경우 REST 기반 설계에서 세션은 관련이 없습니다.유효성 검사를 위해 세션이 필요한 경우 토큰을 사용하거나 IP 주소로 권한을 부여합니다.

마크, 너드 디너 MVC 예를 확인해 보면 논리는 거의 같습니다.

쿠키를 검색하여 현재 세션에서만 설정하면 됩니다.

Global.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

"SampleIdentity" 클래스를 정의해야 합니다. 이 클래스는 nerdinner 프로젝트에서 빌릴 수 있습니다.

문제 해결 방법:

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

Global.asax.cs 에서

마지막 것은 지금 작동하지 않습니다. 이것을 가져가세요. 저에게는 효과가 있었습니다.

WebApiConfig.cs 의 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 
        );

전역.asax

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

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

번째: http://forums.asp.net/t/1773026.aspx/1

LachlanB의 답변에 따라, API 컨트롤러가 특정 디렉터리(예: /api) 내에 있지 않으면 RouteTable을 사용하여 요청을 테스트할 수 있습니다.Routes.GetRouteData 예:

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

저는 asp.net mvc에서도 동일한 문제가 있었습니다. 모든 api 컨트롤러가 상속하는 기본 api 컨트롤러에 이 방법을 적용하여 해결했습니다.

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

그런 다음 api 호출에서 세션에 액세스하려는 경우 다음과 같이 수행합니다.

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

다른 사람들이 게시한 것처럼 제 Global.asax.cs 파일에도 이것이 있습니다. 위의 방법을 사용하여 여전히 필요한지는 모르겠지만, 만약을 위해 여기에 있습니다.

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

또한 세션이 필요한 api 호출에 고정할 수 있는 사용자 지정 필터 특성을 만든 다음 HttpContext를 통해 일반적으로 사용하는 것처럼 api 호출에서 세션을 사용할 수 있습니다.현재의.세션["일부 가치"]:

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

이게 도움이 되길 바랍니다.

저는 @LachlanB 접근법을 따랐고 세션 쿠키가 요청에 있을 때 세션을 사용할 수 있었습니다.누락된 부분은 세션 쿠키가 처음에 클라이언트로 전송되는 방법입니까?

저는 HttpSessionState 가용성을 활성화할 뿐만 아니라 새 세션이 생성될 때 쿠키를 클라이언트로 전송하는 HttpModule을 만들었습니다.

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

@LachlanB의 답변에 언급해야 할 한 가지.

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

하면, 다음과 같이 .if (IsWebApiRequest())

사이트가 웹 양식 페이지와 혼합된 경우 전체 사이트에서 페이지 로드 속도 문제가 발생합니다.

예, 세션은 Rest API와 함께 진행되지 않으며 이러한 관행도 피해야 합니다.그러나 요구 사항에 따라 모든 요청에서 클라이언트 서버가 상태 또는 데이터를 교환하거나 유지할 수 있도록 세션을 유지해야 합니다.따라서 REST 프로토콜을 위반하지 않고 이를 달성하는 가장 좋은 방법은 JWT와 같은 토큰을 통해 통신하는 것입니다.

https://jwt.io/

기본으로 돌아가서 API로 전달하기 위해 단순하게 유지하고 숨겨진 html 값에 세션 값을 저장하는 것이 어떻습니까?

컨트롤러

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" />

자바스크립트

달러(약)ready(함수){

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

    alert(sessionValue);

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

}

언급URL : https://stackoverflow.com/questions/9594229/accessing-session-using-asp-net-web-api

반응형