添加项目文件。
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
using MassTransit;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace IdentityService.Domain.Entities
|
||||
{
|
||||
public class Role : IdentityRole<Guid>
|
||||
{
|
||||
public Role()
|
||||
{
|
||||
Id = NewId.NextGuid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
using IdentityService.Domain.Events;
|
||||
using IM.DomainCommons;
|
||||
using MassTransit;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace IdentityService.Domain.Entities
|
||||
{
|
||||
public class User : IdentityUser<Guid>, IHasCreationTime, IHasDeletionTime, ISoftDelete, IDomainEvents, IHasModificationTime
|
||||
{
|
||||
[NotMapped]
|
||||
public List<INotification> domainEvents = [];
|
||||
|
||||
/// <summary>
|
||||
/// 用户昵称
|
||||
/// </summary>
|
||||
public string NickName { get; private set; } = null!;
|
||||
/// <summary>
|
||||
/// 用户签名
|
||||
/// </summary>
|
||||
public string Description { get; private set; } = "";
|
||||
/// <summary>
|
||||
/// 地区
|
||||
/// </summary>
|
||||
public string Region { get; private set; } = "未知地区";
|
||||
|
||||
/// <summary>
|
||||
/// 用户在线状态
|
||||
/// 0(默认):不在线
|
||||
/// 1:在线
|
||||
/// </summary>
|
||||
//public UserOnlineState OnlineStatus { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 账户状态
|
||||
/// (0:未激活,1:正常,2:封禁)
|
||||
/// </summary>
|
||||
public UserState Status { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户头像链接
|
||||
/// </summary>
|
||||
public string? Avatar { get; private set; }
|
||||
|
||||
public DateTimeOffset CreationTime { get; private set; } = DateTime.Now;
|
||||
|
||||
public DateTimeOffset? Deletion { get; private set; }
|
||||
|
||||
public bool IsDeleted { get; private set; }
|
||||
|
||||
public DateTimeOffset? ModificationTime { get; private set; }
|
||||
|
||||
private User() { }
|
||||
public User(string username, string nickName)
|
||||
{
|
||||
Id = NewId.NextGuid();
|
||||
UserName = username;
|
||||
NickName = nickName;
|
||||
}
|
||||
|
||||
public void Ban(string reason)
|
||||
{
|
||||
if (this.Status == UserState.Banned) return;
|
||||
this.Status = UserState.Banned;
|
||||
|
||||
AddDomainEvent(new UserBannedDomainEvent(this.Id, reason));
|
||||
}
|
||||
|
||||
public void Update(string? nickName, string? region, string? avatar, string? desc)
|
||||
{
|
||||
if (nickName != null)
|
||||
{
|
||||
if (nickName.Trim() == string.Empty) throw new DomainException("昵称不可为空");
|
||||
if (nickName.Length > 20) throw new DomainException("昵称不可大于20");
|
||||
this.NickName = nickName;
|
||||
}
|
||||
|
||||
if (region != null)
|
||||
{
|
||||
if (region.Trim() == string.Empty) throw new DomainException("地区不可为空");
|
||||
if (region.Length > 20) throw new DomainException("地区不可大于20");
|
||||
this.Region = region;
|
||||
}
|
||||
|
||||
if (avatar != null)
|
||||
{
|
||||
|
||||
this.Avatar = avatar;
|
||||
}
|
||||
|
||||
if (desc != null)
|
||||
{
|
||||
this.Description = desc;
|
||||
}
|
||||
|
||||
ModificationTime = DateTime.Now;
|
||||
AddDomainEvent(new UserProfileUpdateDomainEvent(this));
|
||||
}
|
||||
|
||||
public void SoftDelete()
|
||||
{
|
||||
this.IsDeleted = true;
|
||||
}
|
||||
|
||||
public IEnumerable<INotification> GetDomainEvents()
|
||||
{
|
||||
return domainEvents;
|
||||
}
|
||||
|
||||
public void AddDomainEvent(INotification eventItem)
|
||||
{
|
||||
domainEvents.Add(eventItem);
|
||||
}
|
||||
|
||||
public void AddDomainEventIfAbsent(INotification eventItem)
|
||||
{
|
||||
if (!domainEvents.Contains(eventItem))
|
||||
{
|
||||
domainEvents.Add(eventItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearDomainEvents()
|
||||
{
|
||||
domainEvents.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using MediatR;
|
||||
|
||||
namespace IdentityService.Domain.Events
|
||||
{
|
||||
public record UserBannedDomainEvent(Guid UserId, string Reason) : INotification;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using IdentityService.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace IdentityService.Domain.Events
|
||||
{
|
||||
public record UserProfileUpdateDomainEvent(User User) : INotification;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using IdentityService.Domain.Entities;
|
||||
using IM.Commons;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace IdentityService.Domain
|
||||
{
|
||||
public interface IIdRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// 通过用户名查找
|
||||
/// </summary>
|
||||
/// <param name="userName">用户名</param>
|
||||
/// <returns></returns>
|
||||
Task<User?> FindByUserNameAsync(string userName);
|
||||
/// <summary>
|
||||
/// 通过邮箱地址查找
|
||||
/// </summary>
|
||||
/// <param name="Email">邮箱地址</param>
|
||||
/// <returns></returns>
|
||||
Task<User?> FindByEmailAsync(string Email);
|
||||
/// <summary>
|
||||
/// 通过ID查询
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
Task<User?> FindByIdAsync(Guid id);
|
||||
/// <summary>
|
||||
/// 通过手机号查找
|
||||
/// </summary>
|
||||
/// <param name="phone"></param>
|
||||
/// <returns></returns>
|
||||
Task<User?> FindByPhoneAsync(string phone);
|
||||
/// <summary>
|
||||
/// 创建用户
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <returns></returns>
|
||||
Task<IdentityResult> CreateAsync(User user, string password);
|
||||
/// <summary>
|
||||
/// 修改密码
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="password">原密码</param>
|
||||
/// <returns></returns>
|
||||
Task<IdentityResult> ChangePasswordAsync(User user, string password);
|
||||
/// <summary>
|
||||
/// 记录一次失败登录
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
Task<IdentityResult> AccessFailedAsync(User user);
|
||||
/// <summary>
|
||||
/// 获取角色
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
Task<IList<string>> GetRolesAsync(User user);
|
||||
/// <summary>
|
||||
/// 添加角色
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="role"></param>
|
||||
/// <returns></returns>
|
||||
Task<IdentityResult> AddRoleAsync(User user, string role);
|
||||
/// <summary>
|
||||
/// 为登录检查用户名密码
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <param name="lockoutOnFailure">是否记录登录失败</param>
|
||||
/// <returns></returns>
|
||||
Task<SignInResult> CheckForSignInAsync(User user, string password, bool lockoutOnFailure);
|
||||
|
||||
/// <summary>
|
||||
/// 删除用户
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
Task<IdentityResult> RemoveAsync(User user);
|
||||
/// <summary>
|
||||
/// 重置密码
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
Task<(IdentityResult, User?, string password)> ResetPasswordAsync(User user);
|
||||
/// <summary>
|
||||
/// 检查用户名
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
Task<SignInResult> CheckUsernameAsync(string username);
|
||||
/// <summary>
|
||||
/// 检查邮箱
|
||||
/// </summary>
|
||||
/// <param name="email"></param>
|
||||
/// <returns></returns>
|
||||
Task<SignInResult> CheckEmailAsync(string email);
|
||||
/// <summary>
|
||||
/// 检查手机号
|
||||
/// </summary>
|
||||
/// <param name="phone"></param>
|
||||
/// <returns></returns>
|
||||
Task<SignInResult> CheckPhoneAsync(string phone);
|
||||
/// <summary>
|
||||
/// 批量获取用户信息
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
Task<IEnumerable<TResult>> GetUsersAsync<TResult>(ISpecification<User, TResult> specification);
|
||||
Task<IEnumerable<User>> GetUsersAsync(ISpecification<User> specification);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using IdentityService.Domain.Entities;
|
||||
using IM.Commons;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace IdentityService.Domain
|
||||
{
|
||||
public class IdDomainService
|
||||
{
|
||||
private readonly IIdRepository idRepository;
|
||||
public IdDomainService(IIdRepository idRepository)
|
||||
{
|
||||
this.idRepository = idRepository;
|
||||
}
|
||||
|
||||
public async Task<Result<User?>> CreateUserAsync(string userName, string password, string nickName)
|
||||
{
|
||||
SignInResult checkUsername = await idRepository.CheckUsernameAsync(userName);
|
||||
if (!checkUsername.Succeeded)
|
||||
{
|
||||
return Result<User?>.Fail(ResultCode.USER_ALREADY_EXISTS);
|
||||
}
|
||||
return Result<User?>.Success(new User(userName, nickName));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="10.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IM.Commons\IM.Commons.csproj" />
|
||||
<ProjectReference Include="..\DomainCommons\IM.DomainCommons.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace IdentityService.Domain
|
||||
{
|
||||
public enum UserOnlineState
|
||||
{
|
||||
Offline = 0,
|
||||
Online = 1,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace IdentityService.Domain
|
||||
{
|
||||
public enum UserState
|
||||
{
|
||||
Inactive = 0,
|
||||
Normal = 1,
|
||||
Banned = 2
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace IdentityService.Domain.ValueObjects
|
||||
{
|
||||
public class Email
|
||||
{
|
||||
public string Value { get; }
|
||||
public Email(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new ArgumentNullException("邮箱地址不可为空");
|
||||
}
|
||||
|
||||
string pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
|
||||
if (!Regex.IsMatch(value, pattern))
|
||||
{
|
||||
throw new ArgumentException("邮箱地址格式不符合要求");
|
||||
}
|
||||
this.Value = value.ToLowerInvariant();
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public static implicit operator Email(string value)
|
||||
{
|
||||
return new Email(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace IdentityService.Domain.ValueObjects
|
||||
{
|
||||
public class Phone
|
||||
{
|
||||
public string Value { get; }
|
||||
public Phone(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new ArgumentNullException("手机号不可为空");
|
||||
}
|
||||
|
||||
|
||||
string pattern = "^1[3-9]\\d{9}$";
|
||||
if (!Regex.IsMatch(value, pattern))
|
||||
{
|
||||
throw new ArgumentException("手机号格式不符合要求");
|
||||
}
|
||||
Value = value;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public static implicit operator Phone(string value)
|
||||
{
|
||||
return new Phone(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user