Могу ли я получить доступ к базе данных во время запуска в ASP.NET Core?

Недавно я работал над веб-интерфейсом .NET Core. Я только что попробовал аутентификацию с помощью JWT, следуя руководству https://stormpath.com/blog/token-authentication-asp-net-core.

Все шло хорошо, пока мне не пришлось заменить жестко закодированное имя пользователя и пароли в методе GetIdentity с помощью запроса БД и понял, что я не знаю, как получить доступ к БД из этого файла!

Метод, на который я ссылаюсь, показан в ссылке ниже в строке 70. https://github.com/nbarbettini/SimpleTokenProvider/blob/master/test/SimpleTokenProvider.Test/Startup.Auth.cs

Мои вопросы заключаются в следующем.

  • Могу ли я получить доступ к базе данных здесь? Если да, то как?
  • Если это будет метод GetIdentity, или есть лучший способ?

Ответ 1

Да, вы можете получить доступ к базе данных! Код, который работает в методе Configure, может обращаться к любым службам, добавленным в метод ConfigureServices, включая такие вещи, как контексты базы данных.

Например, если у вас есть простой контекст Entity Framework:

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. Конечно, вы можете выбросить свой код и сделать что-то еще лучше.:)

Ответ 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...
}

Добавление служб в контейнер служб делает их доступными в приложение и метод Настройка. Услуги решаются через внедрение зависимости или от ApplicationServices.

Ответ 3

Принятый ответ не работает для сервисов с определенной областью (сервисы с областями создаются для каждого запроса, если вы используете Entity Framework и добавляете контекст с помощью AddDbContext, тогда это так).

При запуске вы можете использовать следующие сервисы (источник):

// 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, как показано в ответе juanora

Ответ 4

Я могу ошибаться на каком-то другом уровне, но решение, которое я нашел, - создать область.

Я передал приложение вместо ctx в GetIdentity, а затем в 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[] { }));
      }
    }
  }