在控制器中更改 ASP.NET Core 2.0 标识连接字符串

Posted

技术标签:

【中文标题】在控制器中更改 ASP.NET Core 2.0 标识连接字符串【英文标题】:Changing ASP.NET Core 2.0 Identity Connection String in Controller 【发布时间】:2018-05-11 00:17:14 【问题描述】:

我正在创建一个基于多租户结构的 Web 应用程序。因此,每个用户请求都会根据主机名将该用户锁定为特定租户(每个租户使用不同的数据库。)我可以设置一般上下文的连接字符串,但我现在不知道如何更改连接ASP.NET Core 2.0 Identity 对象的字符串。

我看到他们让我们这样做的默认方式是在 StartUp.cs 中设置 UseAuthentication()。然后当调用控制器时,DI 会设置 UserManager 和 SignInManager 对象。我假设我需要在每个控制器构造函数中创建新的 UserManager 和 SignInManager 对象,并为该租户传递特定的连接字符串(根本不使用 DI。)

对此有什么想法吗?

澄清:

我希望弄清楚是否可以通过依赖注入将传递的身份对象的数据库连接字符串更改为控制器。

【问题讨论】:

【参考方案1】:
// 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);
    

【讨论】:

仅供参考,我使用了一个单独的数据库(帐户)来存储租户及其用户、许可证和设置。 ;) 我看到在这段代码中你会得到一个可以用于特定租户数据库的连接字符串。您将如何将该连接字符串应用到 AccountController 所需的身份对象? 我创建了一个自定义用户对象,它有一个 account_id(与 Tenant_Id 相同)。我使用 OpenIdDict 进行 oauth 身份验证,它具有创建身份验证票证的交换方法。在这张票(索赔)中,我添加了一个带有此 ID 的额外索赔。 (您也可以使用这个地方来保存您的连接字符串,但是您必须使用一种声明访问器将其转换为具有连接字符串的租户)。租户解析器使用此 ID 来解析连接字符串。如果你愿意,我有一个例子。 我认为您的设置可能有点过于自定义或特定于您的需求而不是我想要的(尽管我最终可能会推出更多自定义的东西。)我正在寻找一种改变的方法传递给控制器​​的现有 UserStore 身份对象上的连接字符串。 据我所知,唯一可行的方法是向身份验证票添加自定义声明并在数据上下文中使用它,如上所示。

以上是关于在控制器中更改 ASP.NET Core 2.0 标识连接字符串的主要内容,如果未能解决你的问题,请参考以下文章

Asp.NET Core 2.0 API 控制器中的 User.Identity.Name 为空

在生产模式下删除 ASP.NET Core 2.0 中的控制台和调试记录器

Asp.net Core 2.0 Identity.TwoFactorRememberMe 到期

ASP.NET Core 2.0 为同一端点结合了 Cookie 和承载授权

asp.net core 2.0 DI将多个IInterface类注入控制器

ASP.Net Core 2.0 - 如何从中间件返回自定义 json 或 xml 响应?