Могу ли я получить доступ к базе данных во время запуска в 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[] { }));
}
}
}