编程语言
首页 > 编程语言> > 每次请求时,ASP.NET身份重新生成身份

每次请求时,ASP.NET身份重新生成身份

作者:互联网

我有一个ASP.NET MVC应用程序,正在使用ASP.NET Identity2.我有一个奇怪的问题.浏览器向我的网站发出的每个请求都会调用ApplicationUser.GenerateUserIdentityAsync.我添加了一些Trace.WriteLine,这是删除IIS输出后的结果:

IdentityConfig.Configuration called
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Content/bootstrap.css
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Scripts/modernizr-2.8.3.js
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Content/site.css
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Scripts/jquery-2.1.3.js
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Scripts/bootstrap.js
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Scripts/respond.js
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Scripts/script.js
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Glimpse.axd?n=glimpse_client&hash=8913cd7e
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Glimpse.axd?n=glimpse_metadata&hash=8913cd7e&callback=glimpse.data.initMetadata
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Glimpse.axd?n=glimpse_request&requestId=6171c2b0-b6e5-4495-b495-4fdaddbe6e8f&hash=8913cd7e&callback=glimpse.data.initData
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/Glimpse.axd?n=glimpse_sprite&hash=8913cd7e
ApplicationUser.GenerateUserIdentityAsync called url: http://localhost:54294/__browserLink/requestData/38254292a54f4595ad26158540adbb6a?version=2

而如果我运行由模板创建的默认MVC应用程序,则会得到以下信息:

IdentityConfig.Configuration called

并且只有在我登录后,它将调用ApplicationUser.GenerateUserIdentityAsync.

我到处都看过我以为可能会看到的东西,但没有发现任何结果.我正在使用(如果有帮助)

StructureMap 3
Elmah
Glimpse
ASP.NET MVC 5
EF6
ASP.NET Identity 2

附加信息

我将用户直接添加到数据库中,而无需使用UserManage.我不确定它是否会对Identity造成任何问题.

更新资料

我删除了数据库,但此事不再发生.怎么了?

更新2

它发生在我的Google Chrome浏览器中(我使用浏览器监视SQL连接),并且删除了存储的Cookie后,并没有发生.可以在其他浏览器中登录导致此问题吗?

更新3

也注销-登录似乎可以暂时解决问题.

解决方法:

我遇到了同样的问题,在研究了源代码和一些侦探性工作之后,我找到了解决方案.问题出在SecurityStampValidator内部,它用作默认的OnValidateIdentity处理程序.请参见源代码here.有趣的部分:

var issuedUtc = context.Properties.IssuedUtc;

// Only validate if enough time has elapsed
var validate = (issuedUtc == null);
if (issuedUtc != null)
{
    var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
    validate = timeElapsed > validateInterval;
}

此部分针对每个请求运行,如果validate为true,则将调用getUserIdCallback和regenerateIdentityCallback(在跟踪输出中可见).这里的问题是,issuedUtc始终是创建cookie的日期,因此,经过validateInterval后,validate始终为true.这解释了您所经历的怪异行为.如果validateInterval为10分钟,则在创建cookie之后(在部署应用程序,清除cookie,注销和再次登录时cookie重置之后),将在10分钟或更长时间内为每个请求运行验证逻辑.

SecurityStampValidator应该根据先前的验证日期(或第一次检查时的发布日期)做出是否验证的决定,但事实并非如此.为使IssuedUtc日期向前发展,有3种可能的解决方案:

>在每个validateInterval中重置cookie,这意味着SingOut和SignIn.类似的解决方案here.这似乎是一项昂贵的操作,尤其是在validateInterval设置为仅几分钟的情况下.
>利用CookieAuthenticationOptions.SlidingExpiration逻辑使Cookie自动重新发出.在this post中解释得很好.

If SlidingExpiration is set to true then the cookie would be re-issued on any request half way through the ExpireTimeSpan. For example, if the user logged in and then made a second request 16 minutes later the cookie would be re-issued for another 30 minutes. If the user logged in and then made a second request 31 minutes later then the user would be prompted to log in.

对于我的情况(Intranet应用程序),不活动30分钟后注销的用户是不可接受的.我需要具有默认的ExpireTimeSpan,即14天.因此,这里的选择是实施某种ajax轮询以延长cookie寿命.听起来要完成此相当简单的方案需要付出很多努力.

>我最后选择使用的最后一个选项是修改SecurityStampValidator实现以具有滑动验证方法.下面的示例代码.请记住在Startup.Auth.cs中用SlidingSecurityStampValidator替换SecurityStampValidator.我将IdentityValidationDates字典添加到原始实现中以存储每个用户的验证日期,然后在检查是否需要验证时使用它.

public static class SlidingSecurityStampValidator
{
    private static readonly IDictionary<string, DateTimeOffset> IdentityValidationDates = new Dictionary<string, DateTimeOffset>();

    public static Func<CookieValidateIdentityContext, Task> OnValidateIdentity<TManager, TUser, TKey>(
        TimeSpan validateInterval, Func<TManager, TUser, Task<ClaimsIdentity>> regenerateIdentityCallback,
        Func<ClaimsIdentity, TKey> getUserIdCallback)
        where TManager : UserManager<TUser, TKey>
        where TUser : class, IUser<TKey>
        where TKey : IEquatable<TKey>
    {
        if (getUserIdCallback == null)
        {
            throw new ArgumentNullException(nameof(getUserIdCallback));
        }

        return async context =>
        {
            var currentUtc = DateTimeOffset.UtcNow;
            if (context.Options != null && context.Options.SystemClock != null)
            {
                currentUtc = context.Options.SystemClock.UtcNow;
            }
            var issuedUtc = context.Properties.IssuedUtc;

            // Only validate if enough time has elapsed
            var validate = issuedUtc == null;
            if (issuedUtc != null)
            {
                DateTimeOffset lastValidateUtc;
                if (IdentityValidationDates.TryGetValue(context.Identity.Name, out lastValidateUtc))
                {
                    issuedUtc = lastValidateUtc;
                }

                var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
                validate = timeElapsed > validateInterval;
            }

            if (validate)
            {
                IdentityValidationDates[context.Identity.Name] = currentUtc;

                var manager = context.OwinContext.GetUserManager<TManager>();
                var userId = getUserIdCallback(context.Identity);
                if (manager != null && userId != null)
                {
                    var user = await manager.FindByIdAsync(userId);
                    var reject = true;

                    // Refresh the identity if the stamp matches, otherwise reject
                    if (user != null && manager.SupportsUserSecurityStamp)
                    {
                        var securityStamp = context.Identity.FindFirstValue(Constants.DefaultSecurityStampClaimType);
                        if (securityStamp == await manager.GetSecurityStampAsync(userId))
                        {
                            reject = false;
                            // Regenerate fresh claims if possible and resign in
                            if (regenerateIdentityCallback != null)
                            {
                                var identity = await regenerateIdentityCallback.Invoke(manager, user);
                                if (identity != null)
                                {
                                    // Fix for regression where this value is not updated
                                    // Setting it to null so that it is refreshed by the cookie middleware
                                    context.Properties.IssuedUtc = null;
                                    context.Properties.ExpiresUtc = null;
                                    context.OwinContext.Authentication.SignIn(context.Properties, identity);
                                }
                            }
                        }
                    }

                    if (reject)
                    {
                        context.RejectIdentity();
                        context.OwinContext.Authentication.SignOut(context.Options.AuthenticationType);
                    }
                }
            }
        };
    }
}

标签:asp-net-identity,iis,asp-net,c,asp-net-mvc
来源: https://codeday.me/bug/20191120/2044748.html