【发布时间】:2015-05-18 06:29:48
【问题描述】:
我正在使用 Asp.net Identity Framework 2.1。我实现了自定义的 ApplicatoinUser、ApplicationRole、ApplicationUserRole,因为我想添加对多租户的支持,即每个用户属于不同的公司,但我在所有这些公司中有 3 个角色,它们是用户、管理员和批准者。
我的 ApplicationUserRole 派生自 IdentityUserRole,并且还有一个属性:CompanyId。此属性将指示用户在此特定公司中的角色。这些自定义类的代码附在底部。
我的问题是当我尝试覆盖 ApplicationUserManager(是的,它也源自 UserManager)的 AddToRoleAsync , IsInRoleAsync 时,我不知道如何处理新的 CompanyId,看起来现有的函数没有'没有收到这些公司 ID(或租户 ID)。
然后,当我尝试使用包含 companyId 重载这些函数时,我在 ApplicatoinUserManager 或其基类中都找不到 db 上下文。
我是否在将tenantId/companyId 添加到应用程序角色的正确轨道上?
我参考了这个答案:SO linkes,还有这个博客。ASP.NET Web Api and Identity 2.0 - Customizing Identity Models and Implementing Role-Based Authorization
我的身份模型:
public class ApplicationUserLogin : IdentityUserLogin<string> { }
public class ApplicationUserClaim : IdentityUserClaim<string>
{
}
public class ApplicationUserRole : IdentityUserRole<string>
{
public string CompanyId { get; set; }
}
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser<string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>//, IAppUser
{
public ApplicationUser()
{
this.Id = Guid.NewGuid().ToString();
}
public virtual string CompanyId { get; set; }
public virtual List<CompanyEntity> Company { get; set; }
public DateTime CreatedOn { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
}
// Must be expressed in terms of our custom UserRole:
public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
public ApplicationRole() {}
public ApplicationRole(string name) : this()
{
this.Name = name;
}
// Add any custom Role properties/code here
public string Description { get; set; }
}
// Most likely won't need to customize these either, but they were needed because we implemented
// custom versions of all the other types:
public class ApplicationUserStore: UserStore<ApplicationUser, ApplicationRole, string,ApplicationUserLogin, ApplicationUserRole,ApplicationUserClaim>, IUserStore<ApplicationUser, string>, IDisposable
{
public ApplicationUserStore()
: this(new IdentityDbContext())
{
base.DisposeContext = true;
}
public ApplicationUserStore(DbContext context)
: base(context)
{
}
}
public class ApplicationRoleStore
: RoleStore<ApplicationRole, string, ApplicationUserRole>,
IQueryableRoleStore<ApplicationRole, string>,
IRoleStore<ApplicationRole, string>, IDisposable
{
public ApplicationRoleStore()
: base(new IdentityDbContext())
{
base.DisposeContext = true;
}
public ApplicationRoleStore(DbContext context)
: base(context)
{
}
}
我的身份配置:
public class ApplicationUserManager
: UserManager<ApplicationUser, string>
{
public ApplicationUserManager(IUserStore<ApplicationUser, string> store)
: base(store) { }
public static ApplicationUserManager Create(
IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(
new UserStore<ApplicationUser, ApplicationRole, string,
ApplicationUserLogin, ApplicationUserRole,
ApplicationUserClaim>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
//RequireNonLetterOrDigit = true,
//RequireDigit = true,
//RequireLowercase = true,
//RequireUppercase = true,
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(
dataProtectionProvider.Create("ASP.NET Identity"));
}
// add sms and email service provider
manager.SmsService = new EMaySmsServiceProvider();
manager.EmailService = new ConcordyaEmailServiceProvider();
return manager;
}
public string GetCurrentCompanyId(string userName)
{
var user = this.FindByName(userName);
if (user == null)
return string.Empty;
var currentCompany = string.Empty;
if (user.Claims.Count > 0)
{
currentCompany = user.Claims.Where(c => c.ClaimType == ConcordyaPayee.Core.Common.ConcordyaClaimTypes.CurrentCompanyId).FirstOrDefault().ClaimValue;
}
else
{
currentCompany = user.CurrentCompanyId;
}
return currentCompany;
}
public override Task<IdentityResult> AddToRoleAsync(string userId, string role, string companyId)
{
return base.AddToRoleAsync(userId, role);
}
#region overrides for unit tests
public override Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
return base.CheckPasswordAsync(user, password);
}
public override Task<ApplicationUser> FindByNameAsync(string userName)
{
return base.FindByNameAsync(userName);
}
#endregion
}
public class ApplicationRoleManager : RoleManager<ApplicationRole>
{
public ApplicationRoleManager(IRoleStore<ApplicationRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(
IdentityFactoryOptions<ApplicationRoleManager> options,
IOwinContext context)
{
return new ApplicationRoleManager(
new ApplicationRoleStore(context.Get<ApplicationDbContext>()));
}
}
【问题讨论】: