ASP.Net Identity多租户登录和注册

时间:2018-09-18 18:16:52

标签: c# webforms asp.net-identity-2

我可以使用一些帮助将ASP.Net Identity扩展到某种简单的多租户设置。此应用程序是WebForms 4.7.1应用程序。我已经在Scott Brady's article上进行过这项工作,但无法在与他的代码稍有不同的代码中使用它。我正在尝试使用其他属性(CompanyId)来实现登录,并且在注册时会接受CompanyId以及电子邮件和密码。我相信我已经正确设置了DBContext,但是单步执行此代码显示我的FindByNameAsync和FindByEmailAsync函数不包含我输入的CompanyId。我显然在某处缺少某些东西。除了Scott的文章外,我真的在有关如何使用附加参数登录的任何其他详细信息方面还是空白。我也不清楚如何在登录期间将此CompanyId值传递到我的 signinManager.PasswordSignIn 函数中。并且在注册过程中,尽管我尝试传递CompanyId,插入函数也不包含我输入的CompanyId。

下面是我的代码(我略有缩写)。在此方面指出我要去哪里的任何帮助将不胜感激:

Register.aspx.cs:

public partial class Register : Page
{
    protected void CreateUser_Click(object sender, EventArgs e)
    {
        var context = HttpContext.Current.GetOwinContext().Get<DecisionLogicIdentity.ApplicationDbContext>();
        var signInManager = HttpContext.Current.GetOwinContext().Get<DecisionLogicIdentity.ApplicationSignInManager>();
        var userStore = new DecisionLogicIdentity.UserStore<DecisionLogicIdentity.ApplicationUser>(context) { CompanyId = Int32.Parse(CompanyId.Text)};
        var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var provider = new DpapiDataProtectionProvider("SampleAppName");
        manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser, int>(provider.Create("SampleTokenName"));

        var user = new DecisionLogicIdentity.ApplicationUser()
        {
            CompanyId = Int32.Parse(CompanyId.Text),
            UserName = Email.Text,
            Email = Email.Text,
            IsExpired = false,
            IsDeleted = false
        };

        IdentityResult result = manager.Create(user, Password.Text);

        if (result.Succeeded)
        {
            user = userStore.FindByEmailAsync(user.Email).GetAwaiter().GetResult();

            string code = manager.GenerateEmailConfirmationToken(user.Id);
            string callbackUrl = IdentityHelper.GetUserConfirmationRedirectUrl(code, user.Id, Request);

            manager.SendEmail(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>.");

            signInManager.SignIn( user, isPersistent: false, rememberBrowser: false);
            IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
        }
        else 
        {
            ErrorMessage.Text = result.Errors.FirstOrDefault();
        }
    }
}

Login.aspx.cs:

public partial class Login : Page
{
    protected void LogIn(object sender, EventArgs e)
    {
        if (IsValid)
        {
            var signinManager = HttpContext.Current.GetOwinContext().GetUserManager<DecisionLogicIdentity.ApplicationSignInManager>();


            // This doen't count login failures towards account lockout
            // To enable password failures to trigger lockout, change to shouldLockout: true
            var result = signinManager.PasswordSignIn(Email.Text, Password.Text, RememberMe.Checked, shouldLockout: true);

            switch (result)
            {
                case SignInStatus.Success:
                    IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
                    break;
                case SignInStatus.LockedOut:
                    Response.Redirect("~/Lockout.aspx");
                    break;
                case SignInStatus.RequiresVerification:
                    break;
                case SignInStatus.Failure:
                default:
                    FailureText.Text = "Invalid login attempt";
                    ErrorMessage.Visible = true;
                    break;
            }
        }
    }
}

UserManager:

public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
    public int CompanyId { get; set; }

    public bool IsExpired { get; set; }

    public bool IsDeleted { get; set; }

    public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
        : base(store)
    {
        //this.EmailService = emailService;
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(
                                new DecisionLogicIdentity.UserStore<ApplicationUser>(
                                context.Get<ApplicationDbContext>() as DatabaseContext));

...
        manager.EmailService = new EmailService();
        manager.SmsService = new SmsService();

        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            var provider = new DpapiDataProtectionProvider("SampleAppName");
            manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser, int>(provider.Create("SampleTokenName"));
        }
        return manager;
    }

}

UserSigninManager:

public class ApplicationSignInManager : SignInManager<ApplicationUser, int>
{
    public int CompanyId { get; set; }

    public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
        : base(userManager, authenticationManager)
    {
    }

    public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
    {
        return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
    }

    public override async Task<SignInStatus> PasswordSignInAsync(string userEmail, string password, bool isPersistent, bool shouldLockout)
    {
        var user = await UserManager.FindByEmailAsync(userEmail);
        if (user != null)
        {
            if (await UserManager.IsLockedOutAsync(user.Id))
            {
                return SignInStatus.LockedOut;
            }
            else
            {
                //If user is not locked out then process login attempt normally
                bool passwordCheck = await UserManager.CheckPasswordAsync(user, password);
                if (passwordCheck)
                {
                    //Reset the lockout if successful
                    if (UserManager.SupportsUserLockout && UserManager.GetAccessFailedCount(user.Id) > 0)
                    {
                        UserManager.ResetAccessFailedCount(user.Id);
                    }

                    var userIdentity = UserManager.CreateIdentity(user, CookieAuthenticationDefaults.AuthenticationType);
                    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie, DefaultAuthenticationTypes.TwoFactorCookie);
                    AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent }, userIdentity);

                    return SignInStatus.Success;
                }
                else
                {
                    if (UserManager.SupportsUserLockout && UserManager.GetLockoutEnabled(user.Id))
                    {
                        UserManager.AccessFailed(user.Id);
                    }
                }
            }

            return SignInStatus.Failure;
        }
        return SignInStatus.Failure;
    }

    public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
    {
        return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
    }
...
}

IdentityUser:

public class IdentityUser : IdentityUser<int,
                            IdentityUserLogin<int>,
                            IdentityUserRole<int>,
                            IdentityUserClaim<int>>, IUser<int>
{
    public int CompanyId { get; set; }

    public bool IsExpired { get; set; }

    public bool IsDeleted { get; set; }

    public IdentityUser()
    {
        Guid.NewGuid().ToString();
    }
}

UserStore:

public class UserStore<T> : IUserRoleStore<T, int>,
                            IUserStore<T, int>,
                            IUserPasswordStore<T, int>,
                            IUserEmailStore<T, int>,
                            IUserLockoutStore<T, int>,
                            IUserTwoFactorStore<T, int>
where T : IdentityUser
{
    private readonly UserRepository<T> _userTable;
    private readonly UserRolesRepository _userRolesTable;

    public int CompanyId { get; set; }
    public bool IsExpired { get; set; }
    public bool IsDeleted { get; set; }

    public UserStore(DatabaseContext databaseContext)
    {
        _userTable = new UserRepository<T>(databaseContext);
        _userRolesTable = new UserRolesRepository(databaseContext);
    }

    public Task CreateAsync(T user)
    {
        if (user == null)
        {
            throw new ArgumentNullException("user");
        }

        user.CompanyId = this.CompanyId;

        return Task.Run(() => _userTable.Insert(user));
    }

    public Task<T> FindByIdAsync(int userId)
    {
        if (userId <= 0)
        {
            throw new ArgumentNullException("userId");
        }
        return Task.Run(() => _userTable.GeTById(userId));
    }

    public Task<T> FindByNameAsync(string userName)
    {
        if (string.IsNullOrEmpty(userName))
        {
            throw new ArgumentException("Null or empty argument: userName");
        }

        return Task.Run(() => _userTable.GeTByName(userName, this.CompanyId));
    }

    public Task<T> FindByEmailAsync(string email)
    {
        if (String.IsNullOrEmpty(email))
        {
            throw new ArgumentNullException("email");
        }

        return Task.Run(() => _userTable.GeTByEmail(email, this.CompanyId));
    }

...

}

用户存储库:

public class UserRepository<T> where T : IdentityUser
{
    private readonly DatabaseContext _databaseContext;

    public UserRepository(DatabaseContext databaseContext)
    {
        _databaseContext = databaseContext;
    }

    internal T GeTByName(string userName, int companyId)
    {
        var user = _databaseContext.SiteUser.SingleOrDefault(u => u.UserName == userName & u.CompanyId == companyId);
        if (user != null)
        {
            T result = (T)Activator.CreateInstance(typeof(T));
            result.Id = user.Id;
            result.CompanyId = user.CompanyId;
            result.UserName = user.UserName;
            result.PasswordHash = user.PasswordHash;
            result.SecurityStamp = user.SecurityStamp;
            result.Email = user.Email;
            result.EmailConfirmed = user.EmailConfirmed;
            result.PhoneNumber = user.PhoneNumber;
            result.PhoneNumberConfirmed = user.PhoneNumberConfirmed;
            result.LockoutEnabled = user.LockoutEnabled;
            result.LockoutEndDateUtc = user.LockoutEndDateUtc;
            result.AccessFailedCount = user.AccessFailedCount;

            return result;
        }
        return null;
    }

    internal T GeTByEmail(string email, int companyId)
    {
        var user = _databaseContext.SiteUser.SingleOrDefault(u => u.Email == email & u.CompanyId == companyId);
        if (user != null)
        {
            T result = (T)Activator.CreateInstance(typeof(T));

            result.Id = user.Id;
            result.CompanyId = user.CompanyId;
            result.UserName = user.UserName;
            result.PasswordHash = user.PasswordHash;
            result.SecurityStamp = user.SecurityStamp;
            result.Email = user.Email;
            result.EmailConfirmed = user.EmailConfirmed;
            result.PhoneNumber = user.PhoneNumber;
            result.PhoneNumberConfirmed = user.PhoneNumberConfirmed;
            result.LockoutEnabled = user.LockoutEnabled;
            result.LockoutEndDateUtc = user.LockoutEndDateUtc;
            result.AccessFailedCount = user.AccessFailedCount;
            return result;
        }
        return null;
    }

    internal int Insert(T user)
    {
        _databaseContext.SiteUser.Add(new SiteUser
        {
            Id = user.Id,
            UserName = user.UserName,
            PasswordHash = user.PasswordHash,
            SecurityStamp = user.SecurityStamp,
            Email = user.Email,
            EmailConfirmed = user.EmailConfirmed,
            PhoneNumber = user.PhoneNumber,
            PhoneNumberConfirmed = user.PhoneNumberConfirmed,
            IsExpired = false,
            LockoutEnabled = user.LockoutEnabled,
            LockoutEndDateUtc = user.LockoutEndDateUtc,
            AccessFailedCount = user.AccessFailedCount
        });

        return _databaseContext.SaveChanges();
    }
...
}

DbContext:

public partial class DatabaseContext : DbContext
{
    static string identityDatabase = ConfigurationManager.AppSettings["IdentityDatabase"].ToString();

    public DatabaseContext()
        : base("name=" + identityDatabase)
    {
    }

    public virtual DbSet<Roles> Roles { get; set; }
    public virtual DbSet<SiteUserClaims> SiteUserClaims { get; set; }
    public virtual DbSet<SiteUserLogins> SiteUserLogins { get; set; }
    public virtual DbSet<SiteUser> SiteUser { get; set; }
    public bool RequireUniqueEmail { get; private set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Roles>()
            .HasMany(e => e.SiteUser)
            .WithMany(e => e.Roles)
            .Map(m => m.ToTable("UserRole").MapLeftKey("RoleId").MapRightKey("SiteUserId"));

        var user = modelBuilder.Entity<SiteUser>();

        user.ToTable("SiteUser")
            .HasMany(e => e.SiteUserClaims)
            .WithRequired(e => e.SiteUser)
            .HasForeignKey(e => e.UserId);

        user.ToTable("SiteUser")
            .HasMany(e => e.SiteUserLogins)
            .WithRequired(e => e.SiteUser)
            .HasForeignKey(e => e.UserId);

        user.Property(u => u.UserName)
            .IsRequired()
            .HasMaxLength(256)
            .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") { IsUnique = true, Order = 1 }));

        user.Property(u => u.CompanyId)
            .IsRequired()
            .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") { IsUnique = true, Order = 2 }));
    }

    protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
    {
        if (entityEntry != null && entityEntry.State == EntityState.Added)
        {
            var errors = new List<DbValidationError>();
            var user = entityEntry.Entity as SiteUser;

            if (user != null)
            {
                if (this.SiteUser.Any(u => string.Equals(u.UserName, user.UserName) && u.CompanyId == user.CompanyId))
                {
                    errors.Add(new DbValidationError("User", string.Format("Username {0} is already taken for CompanyId {1}", user.UserName, user.CompanyId)));
                }

                if (this.RequireUniqueEmail && this.SiteUser.Any(u => string.Equals(u.Email, user.Email) && u.CompanyId == user.CompanyId))
                {
                    errors.Add(new DbValidationError("User", string.Format("Email Address {0} is already taken for CompanyId {1}", user.UserName, user.CompanyId)));
                }
            }
            else
            {
                var role = entityEntry.Entity as IdentityRole;

                if (role != null && this.Roles.Any(r => string.Equals(r.Name, role.Name)))
                {
                    errors.Add(new DbValidationError("Role", string.Format("Role {0} already exists", role.Name)));
                }
            }
            if (errors.Any())
            {
                return new DbEntityValidationResult(entityEntry, errors);
            }
        }

        return new DbEntityValidationResult(entityEntry, new List<DbValidationError>());
    }
}

谢谢!

0 个答案:

没有答案