我可以在 ASP.NET Core 启动期间访问数据库吗?
Can I access a database during startup in ASP.NET Core?
我最近一直在研究 .NET Core web API。我刚刚按照 https://stormpath.com/blog/token-authentication-asp-net-core.
上的指南尝试使用 JWT 进行身份验证
一切都很顺利,直到我不得不用数据库查询替换 GetIdentity
方法中的硬编码用户名和密码,并意识到我不知道如何从这个文件中访问数据库!
下面link第70行显示了我所指的方法。
https://github.com/nbarbettini/SimpleTokenProvider/blob/master/test/SimpleTokenProvider.Test/Startup.Auth.cs
我的问题如下
- 我可以在这里访问数据库吗?如果有怎么办?
- 这里应该是 GetIdentity 方法所在的位置,还是有更好的方法?
是的,您可以访问数据库!在 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 Core Identity。当然,您也可以随意丢弃我的代码并做一些更好的事情。 :)
我在其他层面上可能是错误的,但我找到的解决方案是创建一个范围。
我在 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[] { }));
}
}
}
在 .NET CORE 2.1 上,只需将上下文作为参数传递给 Configure 方法:
public void Configure(IApplicationBuilder app, YourDbContext context, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//do whatever you want with the context here...
}
Adding services to the service container makes them available within
the app and in the Configure method. The services are resolved via
dependency injection or from ApplicationServices.
已接受的答案不适用于范围服务 (scoped services are created per request, if you are using Entity Framework and adding the context with AddDbContext
then 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
方法的参数中传递它,如答案所示
胡安拉
我最近一直在研究 .NET Core web API。我刚刚按照 https://stormpath.com/blog/token-authentication-asp-net-core.
上的指南尝试使用 JWT 进行身份验证一切都很顺利,直到我不得不用数据库查询替换 GetIdentity
方法中的硬编码用户名和密码,并意识到我不知道如何从这个文件中访问数据库!
下面link第70行显示了我所指的方法。 https://github.com/nbarbettini/SimpleTokenProvider/blob/master/test/SimpleTokenProvider.Test/Startup.Auth.cs
我的问题如下
- 我可以在这里访问数据库吗?如果有怎么办?
- 这里应该是 GetIdentity 方法所在的位置,还是有更好的方法?
是的,您可以访问数据库!在 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 Core Identity。当然,您也可以随意丢弃我的代码并做一些更好的事情。 :)
我在其他层面上可能是错误的,但我找到的解决方案是创建一个范围。
我在 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[] { }));
}
}
}
在 .NET CORE 2.1 上,只需将上下文作为参数传递给 Configure 方法:
public void Configure(IApplicationBuilder app, YourDbContext context, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//do whatever you want with the context here...
}
Adding services to the service container makes them available within the app and in the Configure method. The services are resolved via dependency injection or from ApplicationServices.
已接受的答案不适用于范围服务 (scoped services are created per request, if you are using Entity Framework and adding the context with AddDbContext
then 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
方法的参数中传递它,如答案所示
胡安拉