C# 更改控制器中的ASP.NET Core 2.0标识连接字符串
我正在创建一个基于多租户结构的web应用程序。因此,每个用户请求都会根据主机名(每个租户有不同的数据库)将该用户锁定为特定的租户。我可以设置常规上下文的连接字符串,但我现在不知道如何更改ASP.NET Core 2.0标识对象的连接字符串 我看到他们让我们这样做的默认方式是在StartUp.cs中设置UseAuthentication()。然后在调用控制器时,DI设置UserManager和SignInManager对象。我假设我需要在每个控制器构造函数中创建新的UserManager和SignInManager对象,并为该租户传递特定的连接字符串(根本不使用DI) 有什么想法吗 澄清: 我希望弄清楚是否可以通过依赖项注入将传递的标识对象的数据库连接字符串更改为控制器。C# 更改控制器中的ASP.NET Core 2.0标识连接字符串,c#,asp.net-core,asp.net-core-identity,C#,Asp.net Core,Asp.net Core Identity,我正在创建一个基于多租户结构的web应用程序。因此,每个用户请求都会根据主机名(每个租户有不同的数据库)将该用户锁定为特定的租户。我可以设置常规上下文的连接字符串,但我现在不知道如何更改ASP.NET Core 2.0标识对象的连接字符串 我看到他们让我们这样做的默认方式是在StartUp.cs中设置UseAuthentication()。然后在调用控制器时,DI设置UserManager和SignInManager对象。我假设我需要在每个控制器构造函数中创建新的UserManager和Sign
//asp.net core 2的启动类
// Startup class of asp.net core 2
public void ConfigureServices(IServiceCollection services)
{
services.AddMultitenancy<Tenant, TenantResolver>();
string accountsConnection = configuration.GetConnectionString("AccountsConnectionString");
services.AddScoped<LicenseManager>();
services.AddScoped<AccountManager>();
services.AddEntityFrameworkSqlServer()
.AddDbContext<AccountsContext>(options =>
{
options.UseSqlServer(accountsConnection);
})
.AddDbContext<MasterDataContext>(options => options.UseSqlServer(masterdataConnection))
.AddDbContext<DataContext>();
services.AddMvc();
}
// Tenantresolver which get's the connectionstring from the claims. (seperate file/class)
// On authentication i create several claims with one claim with the connectionstring per user.
// I use a seperate accounts database where all the tenants are saved which each of them has his own connectionstring
public class TenantResolver : MemoryCacheTenantResolver<Tenant>
{
private readonly AccountsContext Context;
public TenantResolver(AccountsContext context, IMemoryCache cache, ILoggerFactory logger)
:base(cache, logger)
{
Context = context;
}
protected override string GetContextIdentifier(HttpContext context)
{
return context.User.Claims.Where(r => r.Type == ClaimTypes.AccountIdType).Select(s => s.Value).SingleOrDefault();
}
protected override IEnumerable<string> GetTenantIdentifiers(TenantContext<Tenant> context)
{
return new[] { context.Tenant.Tenant_Id.ToString() };
}
protected override Task<TenantContext<Tenant>> ResolveAsync(HttpContext context)
{
TenantContext<Tenant> tenantContext = null;
string claim = context.User.Claims.Where(r => r.Type == ClaimTypes.AccountIdType).Select(s => s.Value).SingleOrDefault();
var tenant = Context.Accounts
.Where(q => q.IsActive == true && q.Account_Id.ToString() == claim)
.Select(s => new Tenant(s.Account_Id, s.DataStore.DatabaseConnection))
.FirstOrDefault();
if (tenant != null)
{
tenantContext = new TenantContext<Tenant>(tenant);
}
return Task.FromResult(tenantContext);
}
}
// Tenant class where i save the info needed.
public class Tenant
{
public Tenant(
Guid tenant_id,
string database_ConnectionString)
{
Tenant_Id = tenant_id;
Database_ConnectionString = database_ConnectionString;
}
public Guid Tenant_Id { get; set; }
public string Database_ConnectionString { get; set; }
}
// DbContext class which uses the tenant and links the connectionstring to the current tenant.
public class DataContext : DbContext
{
private readonly Tenant Tenant;
public DataContext(DbContextOptions<DataContext> options, Tenant tenant)
: base(options)
{
this.Tenant = tenant;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (Tenant != null)
{
optionsBuilder.UseSqlServer(Tenant.Database_ConnectionString);
}
base.OnConfiguring(optionsBuilder);
}
}
public void配置服务(IServiceCollection服务)
{
services.addMultitenance();
string accountsConnection=configuration.GetConnectionString(“AccountsConnectionString”);
services.addScope();
services.addScope();
services.AddEntityFrameworkSqlServer()
.AddDbContext(选项=>
{
选项。使用SQLServer(accountsConnection);
})
.AddDbContext(选项=>options.UseSqlServer(masterdataConnection))
.AddDbContext();
services.AddMvc();
}
//从声明中获取连接字符串的Tenantresolver。(单独的文件/类)
//在身份验证时,我创建了多个声明,其中一个声明具有每个用户的connectionstring。
//我使用一个单独的帐户数据库,保存所有租户,每个租户都有自己的connectionstring
公共类TenantResolver:MemoryCacheTrantResolver
{
私有只读帐户上下文上下文;
public TenantResolver(AccountsContext上下文、IMemoryCache缓存、iLogger工厂记录器)
:基本(缓存、记录器)
{
上下文=上下文;
}
受保护的重写字符串GetContextIdentifier(HttpContext上下文)
{
返回context.User.Claims.Where(r=>r.Type==ClaimTypes.AccountIdType).Select(s=>s.Value.SingleOrDefault();
}
受保护的重写IEnumerable GetTenantIdentifier(租户上下文)
{
返回新[]{context.Tenant.Tenant_Id.ToString()};
}
受保护的重写任务ResolveAsync(HttpContext上下文)
{
TenantContext TenantContext=null;
string claim=context.User.Claims.Where(r=>r.Type==ClaimTypes.AccountIdType).Select(s=>s.Value.SingleOrDefault();
var tenant=Context.Accounts
.Where(q=>q.IsActive==true&&q.Account\u Id.ToString()==claim)
.Select(s=>新租户(s.Account\u Id,s.DataStore.DatabaseConnection))
.FirstOrDefault();
如果(租户!=null)
{
租户上下文=新租户上下文(租户);
}
返回Task.FromResult(租户上下文);
}
}
//我在其中保存所需信息的租户类。
公屋租户
{
公屋租户(
Guid租户id,
字符串数据库(U连接字符串)
{
租户Id=租户Id;
Database_ConnectionString=Database_ConnectionString;
}
公用Guid租户\u Id{get;set;}
公共字符串数据库\u连接字符串{get;set;}
}
//DbContext类,它使用租户并将connectionstring链接到当前租户。
公共类DataContext:DbContext
{
私人只读租户;
公共数据上下文(DbContextOptions选项,租户)
:基本(选项)
{
this.Tenant=Tenant;
}
配置时受保护的覆盖无效(DBContextOptions Builder Options Builder)
{
如果(租户!=null)
{
optionsBuilder.UseSqlServer(租户.Database\u连接字符串);
}
基本配置(选项生成器);
}
}
FYI,我使用了一个seprate数据库(帐户),在那里我存储租户及其用户、许可证和设置我看到,在这段代码中,您将获得一个连接字符串,该字符串可用于特定租户的数据库。如何将该连接字符串应用于AccountController所需的标识对象?我创建了一个自定义用户对象,该对象具有account\u id(与租户\u id相同)。我使用OpenIdDict进行oauth身份验证,它有一个创建身份验证票证的交换方法。在这个票证(索赔)中,我用这个id添加了一个额外的索赔(您也可以使用这个位置来保存您的connectionstring,但是您必须使用一种claimsaccessor将其转换为具有connectionstring的租户)。tenantresolver使用此id解析connectionstring。如果你愿意,我举一个例子。我认为你的设置可能比我想要的有点过于定制或特定于你的需求(尽管我可能最终会推出更定制的产品)我正在寻找一种方法来更改传递给控制器的已存在UserStore identity对象上的连接字符串。据我所知,唯一可能的方法是向auth票证添加自定义声明,并在datacontext中使用它,如上所示。