Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C端用户 #63

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
5fb8604
新增ClientUser聚合根及相关实体与配置
Zzzzjle Feb 22, 2025
9370c2d
新增ClientUser聚合根的详细业务逻辑实现,包括登录、禁用、启用、修改密码、重置密码、收货地址管理及第三方登录绑定与解绑功能;新增T…
Zzzzjle Feb 22, 2025
76563bd
新增ClientUser聚合根及相关实体的数据库配置;更新ApplicationDbContext以支持新实体的DbSet配置;升级Ent…
Zzzzjle Feb 22, 2025
1879dde
优化ClientUser聚合根中收货地址和第三方登录的逻辑实现;新增收货地址删除功能;重构ClientUserLoginHistory实体…
Zzzzjle Feb 22, 2025
36b4ef0
重构AdminUser相关代码,将AdminUser、Department和Role的相关代码移动到Identity.Admin命名空间下…
Zzzzjle Feb 22, 2025
b489263
新增ClientUser聚合根的详细业务逻辑实现,包括登录、修改密码、禁用、启用、收货地址管理及第三方登录绑定与解绑功能;新增Client…
Zzzzjle Feb 23, 2025
20f2ff1
将AdminUser事件处理器的命名空间从Identity调整为Identity.Admin
Zzzzjle Feb 23, 2025
0c9803c
调整ClientUser登录方法,新增登录时间、登录方式、IP地址和用户代理信息;新增ClientUserLoginEventHandle…
Zzzzjle Feb 23, 2025
6d58171
调整AdminUser相关命名空间为Identity.Admin;新增ClientUser登录、注册功能及相关请求和查询逻辑;优化密码哈希处理
Zzzzjle Feb 27, 2025
018bc91
新增ClientUser控制器及相关请求,添加、获取、更新和删除收货地址;新增绑定和解绑第三方登录功能;密码编辑和用户禁用/启用逻辑
Zzzzjle Mar 3, 2025
2cc7175
优化ClientUser登录逻辑,新增ClientUserLoginResult和ClientUserLoginResponse以处理登录…
Zzzzjle Mar 5, 2025
13c1e97
重构ClientUser请求以删除UserId参数;通过httpcontext获取当前用户;使用框架提供的Jwt管理功能
Zzzzjle Mar 5, 2025
36a9a55
重构ClientUser请求以删除UserId参数;通过httpcontext获取当前用户;使用框架提供的Jwt管理功能
Zzzzjle Mar 5, 2025
11d6539
优化多个配置类,移除冗余的Id生成配置,调整命名空间格式,确保一致性和可读性
Zzzzjle Mar 5, 2025
fc24cd3
重构ClientUser相关控制器,统一用户身份获取方式;新增获取用户信息接口;优化路由定义
Zzzzjle Mar 5, 2025
eba890e
支持RefreshToken
Zzzzjle Mar 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NetCorePal.D3Shop.Admin.Shared.Dtos.Identity
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NetCorePal.D3Shop.Admin.Shared.Dtos.Identity
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using NetCorePal.D3Shop.Admin.Shared.Dtos.Identity;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.DepartmentAggregate;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
using System.ComponentModel.DataAnnotations;

namespace NetCorePal.D3Shop.Admin.Shared.Requests;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using NetCorePal.D3Shop.Admin.Shared.Dtos.Identity;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
using System.ComponentModel.DataAnnotations;

namespace NetCorePal.D3Shop.Admin.Shared.Requests;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.DepartmentAggregate;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.DepartmentAggregate;

namespace NetCorePal.D3Shop.Admin.Shared.Responses;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.DepartmentAggregate;
using NetCorePal.D3Shop.Domain.AggregatesModel.Identity.RoleAggregate;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NetCorePal.D3Shop.Domain.AggregatesModel.Identity.AdminUserAggregate
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
using NetCorePal.D3Shop.Domain.DomainEvents.Identity.Client;
using NetCorePal.Extensions.Domain;
using NetCorePal.Extensions.Primitives;

namespace NetCorePal.D3Shop.Domain.AggregatesModel.Identity.ClientUserAggregate;

public partial record ClientUserId : IInt64StronglyTypedId;

public class ClientUser : Entity<ClientUserId>, IAggregateRoot
{
protected ClientUser()
{
}

public ClientUser(
string nickName,
string avatar,
string phone,
string passwordHash,
string passwordSalt,
string email)
{
NickName = nickName;
Avatar = avatar;
Phone = phone;
PasswordHash = passwordHash;
PasswordSalt = passwordSalt;
Email = email;
CreatedAt = DateTime.Now;
LastLoginAt = DateTime.Now;
}

public ICollection<UserDeliveryAddress> DeliveryAddresses { get; } = [];
public ICollection<UserThirdPartyLogin> ThirdPartyLogins { get; } = [];

public string NickName { get; private set; } = string.Empty;
public string Avatar { get; private set; } = string.Empty;
public string Phone { get; private set; } = string.Empty;
public string PasswordHash { get; private set; } = string.Empty;
public string PasswordSalt { get; private set; } = string.Empty;
public string Email { get; private set; } = string.Empty;
public DateTime CreatedAt { get; private set; }
public DateTime LastLoginAt { get; private set; }
public bool IsDisabled { get; private set; }
public DateTime? DisabledTime { get; private set; }
public string DisabledReason { get; private set; } = string.Empty;
public int PasswordFailedTimes { get; private set; }
public bool IsTwoFactorEnabled { get; private set; }

Check warning on line 48 in src/NetCorePal.D3Shop.Domain/AggregatesModel/Identity/ClientUserAggregate/ClientUser.cs

View workflow job for this annotation

GitHub Actions / build

Remove the unused private setter 'set_IsTwoFactorEnabled'. (https://rules.sonarsource.com/csharp/RSPEC-1144)

/// <summary>
/// 用户登录
/// </summary>
/// <param name="passwordHash"></param>
/// <param name="loginTime"></param>
/// <param name="loginMethod"></param>
/// <param name="ipAddress"></param>
/// <param name="userAgent"></param>
public void Login(
string passwordHash,
DateTime loginTime,
string loginMethod,
string ipAddress,
string userAgent)
{
if (PasswordHash != passwordHash)
{
PasswordFailedTimes++;
throw new KnownException("用户名或密码错误");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里如果throw 的话, PasswordFailedTimes就不会被保存了

}

PasswordFailedTimes = 0;
LastLoginAt = loginTime;
AddDomainEvent(new ClientUserLoginEvent(Id, NickName, loginTime, loginMethod, ipAddress, userAgent));
}

/// <summary>
/// 禁用用户
/// </summary>
/// <param name="reason"></param>
/// <exception cref="KnownException"></exception>
public void Disable(string reason)
{
if (string.IsNullOrWhiteSpace(reason))
throw new KnownException("禁用原因不能为空");

if (IsDisabled) return;
IsDisabled = true;
DisabledTime = DateTime.UtcNow;
DisabledReason = reason.Trim();
}

/// <summary>
/// 启用用户
/// </summary>
public void Enable()
{
if (!IsDisabled) return;
IsDisabled = false;
DisabledTime = null;
DisabledReason = string.Empty;
}

/// <summary>
/// 修改密码
/// </summary>
/// <param name="oldPasswordHash"></param>
/// <param name="newPasswordHash"></param>
public void EditPassword(string oldPasswordHash, string newPasswordHash)
{
if (PasswordHash != oldPasswordHash) throw new KnownException("旧密码不正确");
PasswordHash = newPasswordHash;
}

/// <summary>
/// 重置密码
/// </summary>
/// <param name="newPasswordHash"></param>
public void ResetPassword(string newPasswordHash)
{
PasswordHash = newPasswordHash;
}

/// <summary>
/// 新增收货地址
/// </summary>
/// <param name="address"></param>
/// <param name="recipientName"></param>
/// <param name="phone"></param>
/// <param name="setAsDefault"></param>
/// <returns></returns>
public DeliveryAddressId AddDeliveryAddress(
string address,
string recipientName,
string phone,
bool setAsDefault)
{
var newAddress = new UserDeliveryAddress(
Id,
address,
recipientName,
phone,
setAsDefault
);

if (setAsDefault)
{
// 确保只有一个默认地址
var addr = DeliveryAddresses.SingleOrDefault(a => a.IsDefault);
addr?.UnsetDefault();
}

DeliveryAddresses.Add(newAddress);
return newAddress.Id;
}

/// <summary>
/// 更新收货地址
/// </summary>
/// <param name="deliveryAddressId"></param>
/// <param name="address"></param>
/// <param name="recipientName"></param>
/// <param name="phone"></param>
/// <param name="setAsDefault"></param>
/// <exception cref="KnownException"></exception>
public void UpdateDeliveryAddress(
DeliveryAddressId deliveryAddressId,
string address,
string recipientName,
string phone,
bool setAsDefault)
{
var deliveryAddress = DeliveryAddresses.SingleOrDefault(a => a.Id == deliveryAddressId) ??
throw new KnownException("地址不存在");
deliveryAddress.UpdateDetails(address, recipientName, phone);

if (!setAsDefault) return;

var addr = DeliveryAddresses
.SingleOrDefault(a => a.IsDefault && a.Id != deliveryAddressId);
addr?.UnsetDefault();

if (!deliveryAddress.IsDefault)
deliveryAddress.SetAsDefault();
}

/// <summary>
/// 删除收货地址
/// </summary>
/// <param name="deliveryAddressId"></param>
/// <exception cref="KnownException"></exception>
public void RemoveDeliveryAddress(DeliveryAddressId deliveryAddressId)
{
var deliveryAddress = DeliveryAddresses.SingleOrDefault(a => a.Id == deliveryAddressId) ??
throw new KnownException("地址不存在");
DeliveryAddresses.Remove(deliveryAddress);
}

/// <summary>
/// 绑定第三方登录
/// </summary>
/// <param name="provider"></param>
/// <param name="appId"></param>
/// <param name="openId"></param>
/// <returns></returns>
/// <exception cref="KnownException"></exception>
public ThirdPartyLoginId BindThirdPartyLogin(
ThirdPartyProvider provider,
string appId,
string openId)
{
// 规则:同一提供商下不允许重复绑定
if (ThirdPartyLogins.Any(x => x.Provider == provider && x.AppId == appId))
throw new KnownException("该渠道已绑定,请勿重复操作");

var login = new UserThirdPartyLogin(
Id,
provider,
appId,
openId
);

ThirdPartyLogins.Add(login);
return login.Id;
}

/// <summary>
/// 解绑第三方登录
/// </summary>
/// <param name="loginId"></param>
/// <exception cref="KnownException"></exception>
public void UnbindThirdPartyLogin(ThirdPartyLoginId loginId)
{
var login = ThirdPartyLogins.SingleOrDefault(x => x.Id == loginId) ??
throw new KnownException("登录方式不存在");

ThirdPartyLogins.Remove(login);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace NetCorePal.D3Shop.Domain.AggregatesModel.Identity.ClientUserAggregate;

/// <summary>
/// 第三方登录提供者
/// </summary>
public enum ThirdPartyProvider
{
WeChat = 1,
Qq = 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using NetCorePal.Extensions.Domain;

namespace NetCorePal.D3Shop.Domain.AggregatesModel.Identity.ClientUserAggregate;

public partial record DeliveryAddressId : IInt64StronglyTypedId;

public class UserDeliveryAddress : Entity<DeliveryAddressId>
{
protected UserDeliveryAddress()
{
}

public UserDeliveryAddress(
ClientUserId userId,
string address,
string recipientName,
string phone,
bool isDefault)
{
UserId = userId;
Address = address;
RecipientName = recipientName;
Phone = phone;
IsDefault = isDefault;
}

public ClientUserId UserId { get; private set; } = null!;
public string Address { get; private set; } = string.Empty;
public string RecipientName { get; private set; } = string.Empty;
public string Phone { get; private set; } = string.Empty;
public bool IsDefault { get; private set; }

internal void UpdateDetails(string address, string recipientName, string phone)
{
Address = address;
RecipientName = recipientName;
Phone = phone;
}

internal void SetAsDefault()
{
IsDefault = true;
}

internal void UnsetDefault()
{
IsDefault = false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using NetCorePal.Extensions.Domain;

namespace NetCorePal.D3Shop.Domain.AggregatesModel.Identity.ClientUserAggregate;

public partial record ThirdPartyLoginId : IInt64StronglyTypedId;

public class UserThirdPartyLogin : Entity<ThirdPartyLoginId>
{
protected UserThirdPartyLogin()
{
}

public UserThirdPartyLogin(
ClientUserId userId,
ThirdPartyProvider provider,
string appId,
string openId)
{
UserId = userId;
Provider = provider;
AppId = appId;
OpenId = openId;
BindTime = DateTime.UtcNow;
}

public ClientUserId UserId { get; private set; } = null!;
public ThirdPartyProvider Provider { get; private set; }
public string AppId { get; private set; } = string.Empty;
public string OpenId { get; private set; } = string.Empty;
public DateTime BindTime { get; private set; }

/// <summary>
/// 更新OpenId(重新授权后获取新标识)
/// </summary>
/// <param name="newOpenId"></param>
internal void UpdateOpenId(string newOpenId)
{
OpenId = newOpenId;
}
}
Loading
Loading