hi
You need to replace the built-in Login page and add your step2 choose tenant page.
The system will redirect to a page in authServer where the system will display a list of tenants that the user has been assigned to. user can choose from the tenants assigned to them.!
The redirect code exists on OnGetExternalLoginCallbackAsync method of Volo.Abp.Account.Pro.Public.Web/Pages/Account/Login.cshtml.cs.
so you redirect the user to your custom page on the OnGetExternalLoginCallbackAsync method.
then show the tenant list and set the new tenant for a new user.
You better download the source code of account pro to check the code.
hi
Can you try again, your email was not confirmed.
hi
There are two integration services in the microservices project.
IPermissionIntegrationService and IIdentityUserIntegrationService
It is easy to add a new integration service to your module. https://docs.abp.io/en/abp/latest/Integration-Services
You can give it a try. Feel free to give feedback if you have any problems.
Thanks.
hi
The tenant(TenantId) is set when a user is created.
https://github.com/abpframework/abp/blob/dev/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs#L165
tenantTenantId of a user by ObjectHelpervar user = await UserManager.GetByIdAsync
ObjectHelper.TrySetProperty(user, x => x.TenantId, () => NewTenantId);
hi
I will check if I can reproduce it in a new 8.0 project.
Thanks.
The PR of ABP framework.
https://github.com/abpframework/abp/pull/19523
hi
I updated the code. Can you test the latest one?
I will try to find a better way.
hi
Try to override the protected override void PublishEventsForTrackedEntity(EntityEntry entry) method.
The key changes are:
if (entry.Properties.Where(x => x.IsModified).All(x => x.Metadata.IsForeignKey()))
{
// Skip if only foreign keys are changed.
break;
}
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.LanguageManagement.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TextTemplateManagement.EntityFrameworkCore;
using Volo.Saas.EntityFrameworkCore;
using Volo.Saas.Editions;
using Volo.Saas.Tenants;
using Volo.Abp.Gdpr;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using BugTracker.Examples;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace BugTracker.EntityFrameworkCore;
[ReplaceDbContext(typeof(IIdentityProDbContext))]
[ReplaceDbContext(typeof(ISaasDbContext))]
[ConnectionStringName("Default")]
public class BugTrackerDbContext :
AbpDbContext<BugTrackerDbContext>,
IIdentityProDbContext,
ISaasDbContext
{
/* Add DbSet properties for your Aggregate Roots / Entities here. */
public DbSet<ParentEntity> ParentEntities { get; set; }
#region Entities from the modules
/* Notice: We only implemented IIdentityProDbContext and ISaasDbContext
* and replaced them for this DbContext. This allows you to perform JOIN
* queries for the entities of these modules over the repositories easily. You
* typically don't need that for other modules. But, if you need, you can
* implement the DbContext interface of the needed module and use ReplaceDbContext
* attribute just like IIdentityProDbContext and ISaasDbContext.
*
* More info: Replacing a DbContext of a module ensures that the related module
* uses this DbContext on runtime. Otherwise, it will use its own DbContext class.
*/
// Identity
public DbSet<IdentityUser> Users { get; set; }
public DbSet<IdentityRole> Roles { get; set; }
public DbSet<IdentityClaimType> ClaimTypes { get; set; }
public DbSet<OrganizationUnit> OrganizationUnits { get; set; }
public DbSet<IdentitySecurityLog> SecurityLogs { get; set; }
public DbSet<IdentityLinkUser> LinkUsers { get; set; }
public DbSet<IdentityUserDelegation> UserDelegations { get; set; }
public DbSet<IdentitySession> Sessions { get; set; }
// SaaS
public DbSet<Tenant> Tenants { get; set; }
public DbSet<Edition> Editions { get; set; }
public DbSet<TenantConnectionString> TenantConnectionStrings { get; set; }
#endregion
public BugTrackerDbContext(DbContextOptions<BugTrackerDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureIdentityPro();
builder.ConfigureOpenIddictPro();
builder.ConfigureFeatureManagement();
builder.ConfigureLanguageManagement();
builder.ConfigureSaas();
builder.ConfigureTextTemplateManagement();
builder.ConfigureBlobStoring();
builder.ConfigureGdpr();
/* Configure your own tables/entities inside here */
//builder.Entity<YourEntity>(b =>
//{
// b.ToTable(BugTrackerConsts.DbTablePrefix + "YourEntities", BugTrackerConsts.DbSchema);
// b.ConfigureByConvention(); //auto configure for the base class props
// //...
//});
builder.Entity<ParentEntity>(b =>
{
b.ToTable(BugTrackerConsts.DbTablePrefix + "ParentEntities",
BugTrackerConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.HasMany(x => x.SubEntities).WithOne();
});
builder.Entity<SubEntity>(b =>
{
b.ToTable(BugTrackerConsts.DbTablePrefix + "SubEntities",
BugTrackerConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
});
}
protected override void PublishEventsForTrackedEntity(EntityEntry entry)
{
switch (entry.State)
{
case EntityState.Added:
ApplyAbpConceptsForAddedEntity(entry);
EntityChangeEventHelper.PublishEntityCreatedEvent(entry.Entity);
break;
case EntityState.Modified:
ApplyAbpConceptsForModifiedEntity(entry);
if (entry.Properties.Any(x => x.IsModified && (x.Metadata.ValueGenerated == ValueGenerated.Never || x.Metadata.ValueGenerated == ValueGenerated.OnAdd)))
{
if (entry.Properties.Where(x => x.IsModified).All(x => x.Metadata.IsForeignKey()))
{
// Skip if only foreign keys are changed.
break;
}
if (entry.Entity is ISoftDelete && entry.Entity.As<ISoftDelete>().IsDeleted)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity);
}
else
{
EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity);
}
}
break;
case EntityState.Deleted:
ApplyAbpConceptsForDeletedEntity(entry);
EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity);
break;
}
if (EntityChangeOptions.Value.PublishEntityUpdatedEventWhenNavigationChanges)
{
foreach (var entityEntry in ChangeTracker.Entries().Where(x => x.State == EntityState.Unchanged && AbpEfCoreNavigationHelper.IsEntityEntryNavigationChanged(x)))
{
if (entityEntry.Entity is ISoftDelete && entityEntry.Entity.As<ISoftDelete>().IsDeleted)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entityEntry.Entity);
}
else
{
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityEntry.Entity);
}
}
}
}
}
hi
Please make this repo private I have downloaded the sourecode.
Thanks.