【问题标题】:Can I access a database during startup in ASP.NET Core?我可以在 ASP.NET Core 启动期间访问数据库吗?
【发布时间】:2016-08-02 19:07:19
【问题描述】:

我最近一直在研究 .NET Core Web API。我刚刚按照https://stormpath.com/blog/token-authentication-asp-net-core 上的指南尝试使用 JWT 进行身份验证。

一切都很顺利,直到我不得不用数据库查询替换 GetIdentity 方法中的硬编码用户名和密码,并意识到我不知道如何从这个文件中访问数据库!

我所指的方法显示在下面第 70 行的链接中。 https://github.com/nbarbettini/SimpleTokenProvider/blob/master/test/SimpleTokenProvider.Test/Startup.Auth.cs

我的问题如下。

  1. 我可以在这里访问数据库吗?如果有怎么办?
  2. 这应该是 GetIdentity 方法所在的位置,还是有更好的方法?

【问题讨论】:

    标签: c# .net asp.net-core asp.net-core-mvc .net-core


    【解决方案1】:

    是的,您可以访问数据库!在Configure 方法中运行的代码可以访问在ConfigureServices 方法中添加的任何服务,包括数据库上下文等内容。

    例如,如果您有一个简单的实体框架上下文:

    using Microsoft.EntityFrameworkCore;
    using SimpleTokenProvider.Test.Models;
    
    namespace SimpleTokenProvider.Test
    {
        public class SimpleContext : DbContext
        {
            public SimpleContext(DbContextOptions<SimpleContext> options)
                : base(options)
            {
            }
    
            public DbSet<User> Users { get; set; }
        }
    }
    

    然后你把它添加到ConfigureServices:

    services.AddDbContext<SimpleContext>(opt => opt.UseInMemoryDatabase());
    

    然后,你可以在设置中间件时访问它:

    var context = app.ApplicationServices.GetService<SimpleContext>();
    
    app.UseSimpleTokenProvider(new TokenProviderOptions
    {
        Path = "/api/token",
        Audience = "ExampleAudience",
        Issuer = "ExampleIssuer",
        SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
        IdentityResolver = (username, password) => GetIdentity(context, username, password)
    });
    

    并稍微改写GetIdentity方法:

    private Task<ClaimsIdentity> GetIdentity(SimpleContext context, string username, string password)
    {
        // Access the database using the context
        // Here you'd need to do things like hash the password
        // and do a lookup to see if the user + password hash exists
    }
    

    我是原始样本的作者。抱歉一开始不清楚!我尝试以一种易于提供您自己的功能的方式编写IdentityResolver 委托——例如与您自己的数据库集成(如上所述),或将其连接到 ASP.NET Core Identity。当然,您也可以随意丢弃我的代码并做一些更好的事情。 :)

    【讨论】:

    • 如果您只是将 JWT 添加到 aspnet 身份,您可以传递 signinmanager 而不是 dbcontext: var userManager = app.ApplicationServices .GetService(typeof(UserManager))
    • @xcud 这正是我想要做的,但得到一个错误“无法解析范围服务'Microsoft.AspNetCore.Identity.UserManager`”,我在这里缺少什么?
    • 应该更新样本或在 cmets 中添加这个概念,这让我发疯了好几个小时!谢谢你的回答!
    • 这不适用于范围服务。如果您已将 AddDbContext 与 Entity Framework 一起使用,那么您的 DB 服务是有作用域的。查看我的答案以获得解决方案。
    • @xcud 您需要将身份添加到服务中,例如 services.AddIdentity() 将添加用户和角色,以便您可以在整个应用程序中使用
    【解决方案2】:

    在 .NET CORE 2.1 上,只需将上下文作为参数传递给 Configure 方法:

    public void Configure(IApplicationBuilder app, YourDbContext context, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
            //do whatever you want with the context here...
    }
    

    将服务添加到 服务容器 使它们在 应用程序并在 Configure 方法中。服务通过以下方式解决 依赖注入或来自 ApplicationServices。

    【讨论】:

    • 这是实际且最简单的答案,前提是您已预先将 DbContext 注册为 DI 或隐式注册为 AddDbContext。至少从.net core 2.1开始工作,如this answer中所述(没有检查,适用于3.0 prev)
    • 请问如果您将服务注册为作用域,您仍然可以在Configure 方法中访问它还是只有瞬态和单例在这里工作?
    • @jegtugado 应该可以工作。顺便说一句 AddDbContext 添加为作用域
    【解决方案3】:

    接受的答案不适用于范围服务(scoped 服务是根据请求创建的,如果您使用的是实体框架并使用AddDbContext 添加上下文然后this is the case)。

    您可以按如下方式在启动时使用作用域服务 (source):

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        using (var serviceScope = app.ApplicationServices.CreateScope())
        {
            var services = serviceScope.ServiceProvider;
            var myDbContext = services.GetService<MyDbContext>();
        }
    }
    

    或将其传递给Configure 方法的参数,如答案所示 胡诺拉

    【讨论】:

    【解决方案4】:

    我可能在其他层面上错了,但我找到的解决方案是创建一个范围。

    我在 GetIdentity 中传递了应用程序而不是 ctx,然后在 GetIdentity 中使用范围:

    using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope()) {
        if (serviceScope.ServiceProvider.GetService<YourAppDbContext>() != null) 
        {
          var ctx = serviceScope.ServiceProvider.GetService<YourAppDbContext>();
    
          if (AnAuthenticateMethodHereMaybe(ctx, username, password)) {
            return Task.FromResult(new ClaimsIdentity(new 
    GenericIdentity(username, "Token"), new Claim[] { }));
          }
        }
      }
    

    【讨论】:

      猜你喜欢
      • 2020-07-13
      • 1970-01-01
      • 1970-01-01
      • 2020-05-26
      • 1970-01-01
      • 1970-01-01
      • 2016-05-17
      相关资源
      最近更新 更多