mirror of https://github.com/abpframework/abp.git
csharpabpc-sharpframeworkblazoraspnet-coredotnet-coreaspnetcorearchitecturesaasdomain-driven-designangularmulti-tenancy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
397 lines
12 KiB
397 lines
12 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Security.Claims;
|
|
using JetBrains.Annotations;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Volo.Abp.Auditing;
|
|
using Volo.Abp.Domain.Entities.Auditing;
|
|
using Volo.Abp.Guids;
|
|
using Volo.Abp.Users;
|
|
using Volo.Abp.Timing;
|
|
|
|
namespace Volo.Abp.Identity;
|
|
|
|
public class IdentityUser : FullAuditedAggregateRoot<Guid>, IUser, IHasEntityVersion
|
|
{
|
|
public virtual Guid? TenantId { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the user name for this user.
|
|
/// </summary>
|
|
public virtual string UserName { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the normalized user name for this user.
|
|
/// </summary>
|
|
[DisableAuditing]
|
|
public virtual string NormalizedUserName { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Name for the user.
|
|
/// </summary>
|
|
[CanBeNull]
|
|
public virtual string Name { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Surname for the user.
|
|
/// </summary>
|
|
[CanBeNull]
|
|
public virtual string Surname { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the email address for this user.
|
|
/// </summary>
|
|
public virtual string Email { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the normalized email address for this user.
|
|
/// </summary>
|
|
[DisableAuditing]
|
|
public virtual string NormalizedEmail { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a flag indicating if a user has confirmed their email address.
|
|
/// </summary>
|
|
/// <value>True if the email address has been confirmed, otherwise false.</value>
|
|
public virtual bool EmailConfirmed { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a salted and hashed representation of the password for this user.
|
|
/// </summary>
|
|
[DisableAuditing]
|
|
public virtual string PasswordHash { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// A random value that must change whenever a users credentials change (password changed, login removed)
|
|
/// </summary>
|
|
[DisableAuditing]
|
|
public virtual string SecurityStamp { get; protected internal set; }
|
|
|
|
public virtual bool IsExternal { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a telephone number for the user.
|
|
/// </summary>
|
|
[CanBeNull]
|
|
public virtual string PhoneNumber { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a flag indicating if a user has confirmed their telephone address.
|
|
/// </summary>
|
|
/// <value>True if the telephone number has been confirmed, otherwise false.</value>
|
|
public virtual bool PhoneNumberConfirmed { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a flag indicating if the user is active.
|
|
/// </summary>
|
|
public virtual bool IsActive { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a flag indicating if two factor authentication is enabled for this user.
|
|
/// </summary>
|
|
/// <value>True if 2fa is enabled, otherwise false.</value>
|
|
public virtual bool TwoFactorEnabled { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the date and time, in UTC, when any user lockout ends.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// A value in the past means the user is not locked out.
|
|
/// </remarks>
|
|
[DisableDateTimeNormalization]
|
|
public virtual DateTimeOffset? LockoutEnd { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a flag indicating if the user could be locked out.
|
|
/// </summary>
|
|
/// <value>True if the user could be locked out, otherwise false.</value>
|
|
public virtual bool LockoutEnabled { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the number of failed login attempts for the current user.
|
|
/// </summary>
|
|
public virtual int AccessFailedCount { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// Should change password on next login.
|
|
/// </summary>
|
|
public virtual bool ShouldChangePasswordOnNextLogin { get; protected internal set; }
|
|
|
|
/// <summary>
|
|
/// A version value that is increased whenever the entity is changed.
|
|
/// </summary>
|
|
public virtual int EntityVersion { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the last password change time for the user.
|
|
/// </summary>
|
|
public virtual DateTimeOffset? LastPasswordChangeTime { get; protected set; }
|
|
|
|
//TODO: Can we make collections readonly collection, which will provide encapsulation. But... can work for all ORMs?
|
|
|
|
/// <summary>
|
|
/// Navigation property for the roles this user belongs to.
|
|
/// </summary>
|
|
public virtual ICollection<IdentityUserRole> Roles { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Navigation property for the claims this user possesses.
|
|
/// </summary>
|
|
public virtual ICollection<IdentityUserClaim> Claims { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Navigation property for this users login accounts.
|
|
/// </summary>
|
|
public virtual ICollection<IdentityUserLogin> Logins { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Navigation property for this users tokens.
|
|
/// </summary>
|
|
public virtual ICollection<IdentityUserToken> Tokens { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Navigation property for this organization units.
|
|
/// </summary>
|
|
public virtual ICollection<IdentityUserOrganizationUnit> OrganizationUnits { get; protected set; }
|
|
|
|
protected IdentityUser()
|
|
{
|
|
}
|
|
|
|
public IdentityUser(
|
|
Guid id,
|
|
[NotNull] string userName,
|
|
[NotNull] string email,
|
|
Guid? tenantId = null)
|
|
: base(id)
|
|
{
|
|
Check.NotNull(userName, nameof(userName));
|
|
Check.NotNull(email, nameof(email));
|
|
|
|
TenantId = tenantId;
|
|
UserName = userName;
|
|
NormalizedUserName = userName.ToUpperInvariant();
|
|
Email = email;
|
|
NormalizedEmail = email.ToUpperInvariant();
|
|
ConcurrencyStamp = Guid.NewGuid().ToString("N");
|
|
SecurityStamp = Guid.NewGuid().ToString();
|
|
IsActive = true;
|
|
|
|
Roles = new Collection<IdentityUserRole>();
|
|
Claims = new Collection<IdentityUserClaim>();
|
|
Logins = new Collection<IdentityUserLogin>();
|
|
Tokens = new Collection<IdentityUserToken>();
|
|
OrganizationUnits = new Collection<IdentityUserOrganizationUnit>();
|
|
}
|
|
|
|
public virtual void AddRole(Guid roleId)
|
|
{
|
|
Check.NotNull(roleId, nameof(roleId));
|
|
|
|
if (IsInRole(roleId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Roles.Add(new IdentityUserRole(Id, roleId, TenantId));
|
|
}
|
|
|
|
public virtual void RemoveRole(Guid roleId)
|
|
{
|
|
Check.NotNull(roleId, nameof(roleId));
|
|
|
|
if (!IsInRole(roleId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Roles.RemoveAll(r => r.RoleId == roleId);
|
|
}
|
|
|
|
public virtual bool IsInRole(Guid roleId)
|
|
{
|
|
Check.NotNull(roleId, nameof(roleId));
|
|
|
|
return Roles.Any(r => r.RoleId == roleId);
|
|
}
|
|
|
|
public virtual void AddClaim([NotNull] IGuidGenerator guidGenerator, [NotNull] Claim claim)
|
|
{
|
|
Check.NotNull(guidGenerator, nameof(guidGenerator));
|
|
Check.NotNull(claim, nameof(claim));
|
|
|
|
Claims.Add(new IdentityUserClaim(guidGenerator.Create(), Id, claim, TenantId));
|
|
}
|
|
|
|
public virtual void AddClaims([NotNull] IGuidGenerator guidGenerator, [NotNull] IEnumerable<Claim> claims)
|
|
{
|
|
Check.NotNull(guidGenerator, nameof(guidGenerator));
|
|
Check.NotNull(claims, nameof(claims));
|
|
|
|
foreach (var claim in claims)
|
|
{
|
|
AddClaim(guidGenerator, claim);
|
|
}
|
|
}
|
|
|
|
public virtual IdentityUserClaim FindClaim([NotNull] Claim claim)
|
|
{
|
|
Check.NotNull(claim, nameof(claim));
|
|
|
|
return Claims.FirstOrDefault(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value);
|
|
}
|
|
|
|
public virtual void ReplaceClaim([NotNull] Claim claim, [NotNull] Claim newClaim)
|
|
{
|
|
Check.NotNull(claim, nameof(claim));
|
|
Check.NotNull(newClaim, nameof(newClaim));
|
|
|
|
var userClaims = Claims.Where(uc => uc.ClaimValue == claim.Value && uc.ClaimType == claim.Type);
|
|
foreach (var userClaim in userClaims)
|
|
{
|
|
userClaim.SetClaim(newClaim);
|
|
}
|
|
}
|
|
|
|
public virtual void RemoveClaims([NotNull] IEnumerable<Claim> claims)
|
|
{
|
|
Check.NotNull(claims, nameof(claims));
|
|
|
|
foreach (var claim in claims)
|
|
{
|
|
RemoveClaim(claim);
|
|
}
|
|
}
|
|
|
|
public virtual void RemoveClaim([NotNull] Claim claim)
|
|
{
|
|
Check.NotNull(claim, nameof(claim));
|
|
|
|
Claims.RemoveAll(c => c.ClaimValue == claim.Value && c.ClaimType == claim.Type);
|
|
}
|
|
|
|
public virtual void AddLogin([NotNull] UserLoginInfo login)
|
|
{
|
|
Check.NotNull(login, nameof(login));
|
|
|
|
Logins.Add(new IdentityUserLogin(Id, login, TenantId));
|
|
}
|
|
|
|
public virtual void RemoveLogin([NotNull] string loginProvider, [NotNull] string providerKey)
|
|
{
|
|
Check.NotNull(loginProvider, nameof(loginProvider));
|
|
Check.NotNull(providerKey, nameof(providerKey));
|
|
|
|
Logins.RemoveAll(userLogin =>
|
|
userLogin.LoginProvider == loginProvider && userLogin.ProviderKey == providerKey);
|
|
}
|
|
|
|
[CanBeNull]
|
|
public virtual IdentityUserToken FindToken(string loginProvider, string name)
|
|
{
|
|
return Tokens.FirstOrDefault(t => t.LoginProvider == loginProvider && t.Name == name);
|
|
}
|
|
|
|
public virtual void SetToken(string loginProvider, string name, string value)
|
|
{
|
|
var token = FindToken(loginProvider, name);
|
|
if (token == null)
|
|
{
|
|
Tokens.Add(new IdentityUserToken(Id, loginProvider, name, value, TenantId));
|
|
}
|
|
else
|
|
{
|
|
token.Value = value;
|
|
}
|
|
}
|
|
|
|
public virtual void RemoveToken(string loginProvider, string name)
|
|
{
|
|
Tokens.RemoveAll(t => t.LoginProvider == loginProvider && t.Name == name);
|
|
}
|
|
|
|
public virtual void AddOrganizationUnit(Guid organizationUnitId)
|
|
{
|
|
if (IsInOrganizationUnit(organizationUnitId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
OrganizationUnits.Add(
|
|
new IdentityUserOrganizationUnit(
|
|
Id,
|
|
organizationUnitId,
|
|
TenantId
|
|
)
|
|
);
|
|
}
|
|
|
|
public virtual void RemoveOrganizationUnit(Guid organizationUnitId)
|
|
{
|
|
if (!IsInOrganizationUnit(organizationUnitId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
OrganizationUnits.RemoveAll(
|
|
ou => ou.OrganizationUnitId == organizationUnitId
|
|
);
|
|
}
|
|
|
|
public virtual bool IsInOrganizationUnit(Guid organizationUnitId)
|
|
{
|
|
return OrganizationUnits.Any(
|
|
ou => ou.OrganizationUnitId == organizationUnitId
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use <see cref="IdentityUserManager.ConfirmEmailAsync"/> for regular email confirmation.
|
|
/// Using this skips the confirmation process and directly sets the <see cref="EmailConfirmed"/>.
|
|
/// </summary>
|
|
public virtual void SetEmailConfirmed(bool confirmed)
|
|
{
|
|
EmailConfirmed = confirmed;
|
|
}
|
|
|
|
public virtual void SetPhoneNumberConfirmed(bool confirmed)
|
|
{
|
|
PhoneNumberConfirmed = confirmed;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Normally use <see cref="IdentityUserManager.ChangePhoneNumberAsync"/> to change the phone number
|
|
/// in the application code.
|
|
/// This method is to directly set it with a confirmation information.
|
|
/// </summary>
|
|
/// <param name="phoneNumber"></param>
|
|
/// <param name="confirmed"></param>
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
public void SetPhoneNumber(string phoneNumber, bool confirmed)
|
|
{
|
|
PhoneNumber = phoneNumber;
|
|
PhoneNumberConfirmed = !phoneNumber.IsNullOrWhiteSpace() && confirmed;
|
|
}
|
|
|
|
public virtual void SetIsActive(bool isActive)
|
|
{
|
|
IsActive = isActive;
|
|
}
|
|
|
|
public virtual void SetShouldChangePasswordOnNextLogin(bool shouldChangePasswordOnNextLogin)
|
|
{
|
|
ShouldChangePasswordOnNextLogin = shouldChangePasswordOnNextLogin;
|
|
}
|
|
|
|
public virtual void SetLastPasswordChangeTime(DateTimeOffset? lastPasswordChangeTime)
|
|
{
|
|
LastPasswordChangeTime = lastPasswordChangeTime;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"{base.ToString()}, UserName = {UserName}";
|
|
}
|
|
}
|
|
|