c# - ASP.NET Identity 在登录时对每个页面请求执行数据库查询

标签 c# asp.net vb.net asp.net-identity

我注意到,基于 Identity 2.2.1ASP.NET Web 表单应用程序会在每次页面请求时从数据库中获取登录的用户数据。这是正常的设计行为吗?出于性能原因,用户数据可能会缓存在 session 中。我仔细检查了是否没有在母版页中添加可能导致此行为的额外代码。但不,我使用的是标准 Web 表单模板,没有向母版页添加任何代码。

每个页面请求执行的SQL语句:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Email] AS [Email], 
[Extent1].[EmailConfirmed] AS [EmailConfirmed], 
[Extent1].[PasswordHash] AS [PasswordHash], 
[Extent1].[SecurityStamp] AS [SecurityStamp], 
[Extent1].[PhoneNumber] AS [PhoneNumber], 
[Extent1].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed], 
[Extent1].[TwoFactorEnabled] AS [TwoFactorEnabled], 
[Extent1].[LockoutEndDateUtc] AS [LockoutEndDateUtc], 
[Extent1].[LockoutEnabled] AS [LockoutEnabled], 
[Extent1].[AccessFailedCount] AS [AccessFailedCount], 
[Extent1].[UserName] AS [UserName]
FROM [dbo].[AspNetUsers] AS [Extent1]
WHERE [Extent1].[Id] = @p0

更新1

由于应用程序使用应用服务和 Azure SQL 在 Azure 中运行,每个页面请求背后的数据库查询证据是 Application Insights,如所附屏幕截图所示。

enter image description here

我已开始进一步调查并将数据库移至本地环境。 SQL Server Profiler 显示每个页面请求实际上有 10 个数据库查询。这些是 SELECT 到 AspNetUsersAspNetUserClaimsAspNetUserLogins 等。其中一些执行两次。这不依赖于母版页。不基于母版页的页面会触发与基于母版页的页面相同的 10 次查询。

我对默认的 Visual Studio 模板做了一些修改,如下面的源代码所示。我已经仔细检查过,一旦用户登录,基于相同模板的新项目不会触发任何数据库查询。

修改完成:

  • ApplicationUser 类中的其他字段,通过迁移添加到数据库表
  • 几个配置参数
  • 电子邮件服务配置

源代码:

Global_asax

Public Class Global_asax
Inherits HttpApplication

Sub Application_Start(sender As Object, e As EventArgs)
    ' Fires when the application is started
    RouteConfig.RegisterRoutes(RouteTable.Routes)
    BundleConfig.RegisterBundles(BundleTable.Bundles)
End Sub
End Class

启动

Partial Public Class Startup

' For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301883
Public Sub ConfigureAuth(app As IAppBuilder)
    'Configure the db context, user manager and signin manager to use a single instance per request
    app.CreatePerOwinContext(AddressOf ApplicationDbContext.Create)
    app.CreatePerOwinContext(Of ApplicationUserManager)(AddressOf ApplicationUserManager.Create)
    app.CreatePerOwinContext(Of ApplicationSignInManager)(AddressOf ApplicationSignInManager.Create)

    ' Enable the application to use a cookie to store information for the signed in user
    app.UseCookieAuthentication(New CookieAuthenticationOptions() With {
        .AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        .Provider = New CookieAuthenticationProvider() With {
            .OnValidateIdentity = SecurityStampValidator.OnValidateIdentity(Of ApplicationUserManager, ApplicationUser)(
                validateInterval:=TimeSpan.FromMinutes(0),
                regenerateIdentity:=Function(manager, user) user.GenerateUserIdentityAsync(manager))},
        .LoginPath = New PathString("/Account/Login"),
        .ExpireTimeSpan = TimeSpan.FromMinutes(20),
        .SlidingExpiration = True})

    ' Use a cookie to temporarily store information about a user logging in with a third party login provider
    'app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie)

    ' Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
    'app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5))

    ' Enables the application to remember the second login verification factor such as phone or email.
    ' Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
    ' This is similar to the RememberMe option when you log in.
    'app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie)

    ' Uncomment the following lines to enable logging in with third party login providers
    'app.UseMicrosoftAccountAuthentication(
    '    clientId:= "",
    '    clientSecret:= "")

    'app.UseTwitterAuthentication(
    '   consumerKey:= "",
    '   consumerSecret:= "")

    'app.UseFacebookAuthentication(
    '   appId:= "",
    '   appSecret:= "")

    'app.UseGoogleAuthentication(New GoogleOAuth2AuthenticationOptions() With {
    '   .ClientId = "",
    '   .ClientSecret = ""})
End Sub
End Class

IdentityConfig.vb

Public Class EmailService
Implements IIdentityMessageService
Public Function SendAsync(message As IdentityMessage) As Task Implements IIdentityMessageService.SendAsync
    ' Plug in your email service here to send an email.
    'Return Task.FromResult(0)
    Dim client As New Net.Mail.SmtpClient(DTAppSettings.SendGrid_SMTPServer, 587)
    Dim credentials As New Net.NetworkCredential(DTAppSettings.SendGrid_Username, DTAppSettings.SendGrid_Password)
    client.Credentials = credentials
    client.EnableSsl = True
    Dim mailmessage As New Net.Mail.MailMessage With {
        .From = New Net.Mail.MailAddress(DTAppSettings.SendGrid_FromAddress, DTAppSettings.SendGrid_FromName),
        .Subject = message.Subject,
        .Body = message.Body,
        .IsBodyHtml = True
    }
    mailmessage.To.Add(message.Destination)
    Return client.SendMailAsync(mailmessage)
End Function
End Class

Public Class SmsService
Implements IIdentityMessageService
Public Function SendAsync(message As IdentityMessage) As Task Implements IIdentityMessageService.SendAsync
    ' Plug in your SMS service here to send a text message.
    Return Task.FromResult(0)
End Function
End Class

' Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.
Public Class ApplicationUserManager
Inherits UserManager(Of ApplicationUser)
Public Sub New(store As IUserStore(Of ApplicationUser))
    MyBase.New(store)
End Sub

Public Shared Function Create(options As IdentityFactoryOptions(Of ApplicationUserManager), context As IOwinContext) As ApplicationUserManager
    Dim manager = New ApplicationUserManager(New UserStore(Of ApplicationUser)(context.[Get](Of ApplicationDbContext)()))
    ' Configure validation logic for usernames
    manager.UserValidator = New UserValidator(Of ApplicationUser)(manager) With {
      .AllowOnlyAlphanumericUserNames = False,
      .RequireUniqueEmail = True
    }

    ' Configure validation logic for passwords
    manager.PasswordValidator = New PasswordValidator() With {
      .RequiredLength = 6,
      .RequireNonLetterOrDigit = True,
      .RequireDigit = True,
      .RequireLowercase = True,
      .RequireUppercase = True
    }
    ' Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user. 
    ' You can write your own provider and plug in here.
    'manager.RegisterTwoFactorProvider("Phone Code", New PhoneNumberTokenProvider(Of ApplicationUser)() With {
    '  .MessageFormat = "Your security code is {0}"
    '})
    'manager.RegisterTwoFactorProvider("Email Code", New EmailTokenProvider(Of ApplicationUser)() With {
    '  .Subject = "Security Code",
    '  .BodyFormat = "Your security code is {0}"
    '})

    ' Configure user lockout defaults
    manager.UserLockoutEnabledByDefault = True
    manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5)
    manager.MaxFailedAccessAttemptsBeforeLockout = 5

    manager.EmailService = New EmailService()
    manager.SmsService = New SmsService()
    Dim dataProtectionProvider = options.DataProtectionProvider
    If dataProtectionProvider IsNot Nothing Then
        manager.UserTokenProvider = New DataProtectorTokenProvider(Of ApplicationUser)(dataProtectionProvider.Create("ASP.NET Identity")) With {
            .TokenLifespan = TimeSpan.FromHours(1)
            }
    End If
    Return manager
End Function
End Class

Public Class ApplicationSignInManager
Inherits SignInManager(Of ApplicationUser, String)
Public Sub New(userManager As ApplicationUserManager, authenticationManager As IAuthenticationManager)
    MyBase.New(userManager, authenticationManager)
End Sub

Public Overrides Function CreateUserIdentityAsync(user As ApplicationUser) As Task(Of ClaimsIdentity)
    Return user.GenerateUserIdentityAsync(DirectCast(UserManager, ApplicationUserManager))
End Function

Public Shared Function Create(options As IdentityFactoryOptions(Of ApplicationSignInManager), context As IOwinContext) As ApplicationSignInManager
    Return New ApplicationSignInManager(context.GetUserManager(Of ApplicationUserManager)(), context.Authentication)
End Function
End Class

最佳答案

问题与这段代码有关:

.OnValidateIdentity = SecurityStampValidator.OnValidateIdentity(Of ApplicationUserManager, 
    ApplicationUser)(validateInterval:=TimeSpan.FromMinutes(0),

尝试更大的值,例如.FromMinutes(15)

由于 validateInterval 为 0,因此它基本上是在每次页面加载时重新验证身份信息。

关于c# - ASP.NET Identity 在登录时对每个页面请求执行数据库查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45205085/

相关文章:

c# - 将字符串转换为数字?

c# - 汇总所有节点

c# - :disabled attribute on my button does not seem to work

c# - HttpWebRequest 到 HttpClient post 请求

vb.net - 在 Visual Studio 2008 中清理 Designer.vb 文件

.net - 如何从流中加载非托管 DLL?

c# - 可以使用 ReactiveUI 根据两个列表执行

asp.net - asp.net 角色提供者什么时候生死?

asp.net - 如何按需加载两个 ASP.NET UserControl?

c# - 始终使用异步/等待在 ASP.NET Web 窗体中的浏览器中加载页面