Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Web API请求上的滑动会话_C#_.net_Asp.net Mvc_Session_Asp.net Web Api2 - Fatal编程技术网

C# Web API请求上的滑动会话

C# Web API请求上的滑动会话,c#,.net,asp.net-mvc,session,asp.net-web-api2,C#,.net,Asp.net Mvc,Session,Asp.net Web Api2,更新:它似乎正在尝试在ApplyResponseGrantAsync中写入新的cookie标头,但无法写入,因为它引发了一个异常,即标头已经发送。 更新:更清楚。如何在Web API请求期间将Set Cookie头添加到XHR响应中 TL;博士问题是应用程序通过MVC进行身份验证,但大量使用Web API。Web API请求不会滑动会话,即使它们使用了身份验证属性——几乎可以肯定,因为这是一个cookie响应 我有一个结合了MVC和WebAPI的应用程序。在大多数情况下,MVC视图只加载发出大量

更新:它似乎正在尝试在
ApplyResponseGrantAsync
中写入新的cookie标头,但无法写入,因为它引发了一个异常,即标头已经发送。

更新:更清楚。如何在Web API请求期间将
Set Cookie
头添加到XHR响应中


TL;博士问题是应用程序通过MVC进行身份验证,但大量使用Web API。Web API请求不会滑动会话,即使它们使用了
身份验证
属性——几乎可以肯定,因为这是一个cookie响应

我有一个结合了MVC和WebAPI的应用程序。在大多数情况下,MVC视图只加载发出大量Web API请求的SPA这很好,但会话滑动不适用于Web API请求。

我可以看到
CookieAuthenticationHandler
ApplyResponseGrantAsync
中滑动会话的位置,但我需要在每个Web API请求上强制执行该操作

model.Properties.IssuedUtc = new DateTimeOffset?(this._renewIssuedUtc);
model.Properties.ExpiresUtc = new DateTimeOffset?(this._renewExpiresUtc);
if (this.Options.SessionStore != null && this._sessionKey != null)
{
  await this.Options.SessionStore.RenewAsync(this._sessionKey, model);
  ClaimsIdentity identity = new ClaimsIdentity((IEnumerable<Claim>) new Claim[1]
  {
    new Claim("Microsoft.Owin.Security.Cookies-SessionId", this._sessionKey)
  }, this.Options.AuthenticationType);
    model = new AuthenticationTicket(identity, (AuthenticationProperties) null);
}
string cookieValue = this.Options.TicketDataFormat.Protect(model);
if (model.Properties.IsPersistent)
  cookieOptions.Expires = new DateTime?(this._renewExpiresUtc.ToUniversalTime().DateTime);
this.Options.CookieManager.AppendResponseCookie(this.Context, this.Options.CookieName, cookieValue, cookieOptions);
model.Properties.IssuedUtc=新的日期时间偏移量?(此.\u续订IssuedUtc);
model.Properties.ExpiresUtc=新的DateTimeOffset?(此.\u续订ExpiresUtc);
if(this.Options.SessionStore!=null&&this.\u sessionKey!=null)
{
等待this.Options.SessionStore.RenewaAsync(this.\u sessionKey,model);
索赔实体标识=新索赔实体((IEnumerable)新索赔[1]
{
新声明(“Microsoft.Owin.Security.Cookies SessionId”,this.\u sessionKey)
},this.Options.AuthenticationType);
模型=新的AuthenticationTicket(identity,(AuthenticationProperties)null);
}
string cookieValue=this.Options.TicketDataFormat.Protect(模型);
if(model.Properties.IsPersistent)
cookieOptions.Expires=新的日期时间?(此._renewExpiresUtc.ToUniversalTime().DateTime);
this.Options.CookieManager.AppendResponseCookie(this.Context,this.Options.CookieName,cookieValue,cookieOptions);
有人知道怎么强迫吗

身份验证设置
app.UseCookieAuthentication(新的CookieAuthenticationOptions
{
AuthenticationType=DefaultAuthenticationTypes.ApplicationOkie,
LoginPath=新路径字符串(“/Account/Login”),
Provider=新CookieAuthenticationProvider
{
OnValidateIdentity=SecurityStampValidator.OnValidateIdentity(
validateInterval:TimeSpan.FromMinutes(15),
regenerateIdentity:(管理器,用户)=>user.GenerateUserIdentityAsync(管理器))
},
slidengexpiration=true,
ExpireTimeSpan=时间跨度。从分钟(1)
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie,TimeSpan.FromMinutes(5));
app.useTowFactoryMemberBrowserCookie(DefaultAuthenticationTypes.TwoFactoryRememberBrowserCookie);

根据
CookieAuthenticationMiddleware
来源,如果您将
CookieAuthenticationOptions
SlidingExpiration
设置为true,您的会话将在每次请求时续订。你可以检查一下,看看你自己

我想我找到了您的问题,基于为了更新cookie,SignIn方法的
AuthenticationProperties
AllowRefresh
属性应该为true。我猜这是你的问题。

如果我没有记错的话,您正在使用'ApplicationSignInManager.SignInAsync()'登录您的用户。不幸的是,基于[implementation][2],无法传递参数来设置'AllowRefresh',因此我建议重写SignInAsync方法并将'AllowRefresh'设置为true,然后看看它是否有效。 更新

这是另一种猜测,它可能会解决你的问题。基于cookie的会话将在其生命周期仅过了50%时续订,当我查看代码时,我发现没有办法覆盖它。我建议通过添加一个
中间件来更新cookie,该中间件将
在每个请求上插入用户,从而在每个请求上创建一个新的cookie,无论请求是在WebAPI还是MVC中

在app.UseCookieAuthentication之后添加中间件

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
        validateInterval: TimeSpan.FromMinutes(15),
        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes(1)
});

app.Use(async (context, next) =>
{
    var result = await context.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ApplicationCookie);
    if (result != null)
    {
        result.Properties.ExpiresUtc = null;
        result.Properties.IssuedUtc = null;
        context.Authentication.SignIn(result.Properties, result.Identity);
    }
    await next();
});
app.UseCookieAuthentication(新的CookieAuthenticationOptions
{
AuthenticationType=DefaultAuthenticationTypes.ApplicationOkie,
LoginPath=新路径字符串(“/Account/Login”),
Provider=新CookieAuthenticationProvider
{
OnValidateIdentity=SecurityStampValidator.OnValidateIdentity(
validateInterval:TimeSpan.FromMinutes(15),
regenerateIdentity:(管理器,用户)=>user.GenerateUserIdentityAsync(管理器))
},
slidengexpiration=true,
ExpireTimeSpan=时间跨度。从分钟(1)
});
应用程序使用(异步(上下文,下一步)=>
{
var result=wait context.Authentication.authenticateSync(DefaultAuthenticationTypes.ApplicationOkie);
如果(结果!=null)
{
result.Properties.ExpiresUtc=null;
result.Properties.IssuedUtc=null;
context.Authentication.SignIn(result.Properties,result.Identity);
}
等待下一个();
});
基本上,您可以将
SlidingExpiration
设置为false,因为这与此解决方法无关,而且通过这种方式
CookieAuthentication
上的
OnValidateIdentity
无法每30分钟重新加载一次用户声明,因为每次请求都会刷新IssuedUTC,如果需要,您必须修改此中间件并编写一个自定义的
OnValidateIdentity

通常,如果您在web.config中启用slidingExpiration,它将起作用。您无需手动重新生成新cookie。对于您的场景,我建议您使用跟踪工具,例如Fiddler。刷新页面时,可以从Fiddler检查cookie过期时间是否重置


在读取标头时,
ApplyResponseAsync()
,以及随后的
ApplyResponseGrantAsync()
ApplyResponseChallengeAsync()
,也将调用一次
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
        validateInterval: TimeSpan.FromMinutes(15),
        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes(1)
});

app.Use(async (context, next) =>
{
    var result = await context.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ApplicationCookie);
    if (result != null)
    {
        result.Properties.ExpiresUtc = null;
        result.Properties.IssuedUtc = null;
        context.Authentication.SignIn(result.Properties, result.Identity);
    }
    await next();
});
<forms loginUrl="/account/login" name="authy" path="/" slidingExpiration="true" cookieless="UseCookies"/>
       protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext.ActionDescriptor.ActionName=="YourWebAPIName")
            {
                filterContext.HttpContext.Response.AddHeader("Set-Cookie","CookieName=CookieValue");           
            }
        //You can replace the former if with a more general one like checking:
        //filterContext.Result.GetType() and see if it is of the type JsonResult

            base.OnActionExecuted(filterContext);
        }
public class WebApiResponseFilter : ActionFilterAttribute
{
    private ILogUtils logUtils;

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);

        if (logUtils == null)
        {
            logUtils = StructureMapConfig.Container.GetInstance<ILogUtils>();
        }

        var httpContext = HttpContext.Current;

        var actionDescriptor = actionExecutedContext.ActionContext.ActionDescriptor;

        var requestId = httpContext.Request.Headers.GetValues("X-RequestId").First();
        var userId = httpContext.User.Identity.GetUserId();
        var userName = httpContext.User.Identity.GetUserName();

        var responseContent = actionExecutedContext.Response.Content;
        if (responseContent == null)
        {
            logUtils.LogUsage($"RESPONSE LOG ipAddress:{httpContext.Request.UserHostAddress} requestId:{requestId} userId:{userId} userName:{userName} action:{actionDescriptor.ControllerDescriptor.ControllerName}.{actionDescriptor.ActionName} response:n/a");
        }
        else
        {
            var response = Task.Run(async () => await responseContent.ReadAsStringAsync()).Result;
            response = AesManager.EncryptData(response);
            logUtils.LogUsage($"RESPONSE LOG ipAddress:{httpContext.Request.UserHostAddress} requestId:{requestId} userId:{userId} userName:{userName} action:{actionDescriptor.ControllerDescriptor.ControllerName}.{actionDescriptor.ActionName} response:{response}");
        }
    }
}