添加项目文件。

This commit is contained in:
2026-05-09 17:06:30 +08:00
parent c60f5fe117
commit 720ef957d4
378 changed files with 14843 additions and 0 deletions
@@ -0,0 +1,24 @@
using AutoMapper;
using IdentityService.WebApi.Applications.Dtos.Common;
namespace IdentityService.WebApi.Applications.Auth
{
public class AuthMappingProfile : Profile
{
public AuthMappingProfile()
{
CreateMap<Domain.Entities.User, UserResponse>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.UserName))
.ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email))
.ForMember(dest => dest.Phone, opt => opt.MapFrom(src => src.PhoneNumber))
.ForMember(dest => dest.Region, opt => opt.MapFrom(src => src.Region))
.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description))
.ForMember(dest => dest.Avatar, opt => opt.MapFrom(src => src.Avatar))
.ForMember(dest => dest.CreationTime, opt => opt.MapFrom(src => src.CreationTime))
.ForMember(dest => dest.Deletion, opt => opt.MapFrom(src => src.Deletion))
.ForMember(dest => dest.NickName, opt => opt.MapFrom(src => src.NickName))
;
}
}
}
@@ -0,0 +1,97 @@
using AutoMapper;
using IdentityService.Domain;
using IdentityService.WebApi.Applications.Dtos;
using IdentityService.WebApi.Applications.Dtos.Common;
using IM.Commons;
using IM.Jwt;
using Microsoft.Extensions.Options;
using System.Security.Claims;
namespace IdentityService.WebApi.Applications.Auth
{
public class AuthService
{
private readonly ITokenService tokenService;
private readonly IIdRepository idRepository;
private readonly IOptions<JwtOptions> jwtOptions;
private readonly IdDomainService idDomainService;
private readonly IMapper mapper;
public AuthService(ITokenService tokenService, IIdRepository idRepository,
IOptions<JwtOptions> options, IdDomainService idDomainService,
IMapper mapper
)
{
this.tokenService = tokenService;
this.idRepository = idRepository;
jwtOptions = options;
this.idDomainService = idDomainService;
this.mapper = mapper;
}
public async Task<Result<LoginResponse>> LoginAsync(string username, string password)
{
var user = await idRepository.FindByUserNameAsync(username);
if (user is null)
{
return Result<LoginResponse>.Fail(ResultCode.USER_NOT_FOUND);
}
var idResult = await idRepository.CheckForSignInAsync(user, password, true);
if (!idResult.Succeeded)
{
return Result<LoginResponse>.Fail(ResultCode.PASSWORD_ERROR);
}
var token = await BuildTokenAsync(user);
var refreshToken = await tokenService.CreateRefreshTokenAsync(user.Id);
return Result<LoginResponse>.Success(new LoginResponse(user.Id, token, refreshToken, null));
}
public async Task<Result<UserResponse?>> RegisterAsync(string userName, string password, string nickName)
{
var userResult = await idDomainService.CreateUserAsync(userName, password, nickName);
if (!userResult.Succeeded)
return Result<UserResponse?>.Fail(userResult);
var idResult = await idRepository.CreateAsync(userResult.Data!, password);
if (!idResult.Succeeded)
{
var msg = idResult.Errors.FirstOrDefault();
return Result<UserResponse?>.Fail(
ResultCode.REGISTER_ERROR,
msg?.Description ?? ResultCode.REGISTER_ERROR.GetDescription());
}
return Result<UserResponse?>.Success(mapper.Map<UserResponse>(userResult.Data));
}
public async Task<Result<LoginResponse>> RefreshAsync(string refreshToken)
{
var validateRes = await tokenService.ValidateRefreshTokenAsync(refreshToken);
if (!validateRes.ok)
{
return Result<LoginResponse>.Fail(ResultCode.AUTH_FAILED);
}
var user = await idRepository.FindByIdAsync(validateRes.userId);
if (user is null)
{
return Result<LoginResponse>.Fail(ResultCode.USER_NOT_FOUND);
}
var token = await BuildTokenAsync(user);
return Result<LoginResponse>.Success(new LoginResponse(user.Id, token, refreshToken, null));
}
private async Task<string> BuildTokenAsync(Domain.Entities.User user)
{
var roles = await idRepository.GetRolesAsync(user);
List<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
foreach (string role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
return tokenService.GetToken(claims, jwtOptions.Value);
}
}
}
@@ -0,0 +1,16 @@
namespace IdentityService.WebApi.Applications.Dtos.Common
{
public class UserResponse
{
public Guid Id { get; set; }
public string UserName { get; set; }
public string NickName { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
public string Region { get; set; }
public string Description { get; set; }
public string? Avatar { get; set; }
public DateTimeOffset CreationTime { get; set; }
public DateTimeOffset? Deletion { get; set; }
}
}
@@ -0,0 +1,18 @@
namespace IdentityService.WebApi.Applications.Dtos
{
public class LoginResponse
{
public Guid UserId { get; init; }
public string Token { get; init; }
public string RefreshToken { get; init; }
public DateTime? Expired { get; init; }
public LoginResponse(Guid userId, string token, string refreshToken, DateTime? expired)
{
UserId = userId;
Token = token;
RefreshToken = refreshToken;
Expired = expired;
}
}
}
@@ -0,0 +1,32 @@
using IdentityService.Domain.Events;
using IM.Commons.IntegrationEvents;
using MassTransit;
using MediatR;
namespace IdentityService.WebApi.Applications.EventHandler
{
public class UserProfileUpdateHandler : INotificationHandler<UserProfileUpdateDomainEvent>
{
private readonly IPublishEndpoint endpoint;
public UserProfileUpdateHandler(IPublishEndpoint endpoint)
{
this.endpoint = endpoint;
}
public async Task Handle(UserProfileUpdateDomainEvent notification, CancellationToken cancellationToken)
{
await endpoint.Publish(new UserProfileUpdateEvent
{
CorrelationId = notification.User.Id,
Avatar = notification.User.Avatar,
Description = notification.User.Description,
Email = notification.User.Email,
NickName = notification.User.NickName,
Phone = notification.User.PhoneNumber,
Status = notification.User.Status.ToString(),
UserId = notification.User.Id
});
}
}
}
@@ -0,0 +1,35 @@
using AutoMapper;
using IdentityService.WebApi.Applications.Dtos.Common;
using IM.Commons;
using System.Linq.Expressions;
namespace IdentityService.WebApi.Applications.User
{
public class UserResponseFindSpecification : ISpecification<Domain.Entities.User, UserResponse>
{
private readonly IEnumerable<Guid> Ids;
public UserResponseFindSpecification(IEnumerable<Guid> ids, IMapper mapper)
{
Ids = ids;
Criteria = u => Ids.Contains(u.Id);
Select = u => new UserResponse
{
Avatar = u.Avatar,
CreationTime = u.CreationTime,
Deletion = u.Deletion,
Description = u.Description,
Email = u.Email,
Id = u.Id,
Phone = u.PhoneNumber,
Region = u.Region,
UserName = u.UserName
};
}
public Expression<Func<Domain.Entities.User, bool>> Criteria { get; }
public List<Expression<Func<Domain.Entities.User, object>>> Includes { get; }
public Expression<Func<Domain.Entities.User, UserResponse>> Select { get; }
}
}
@@ -0,0 +1,54 @@
using AutoMapper;
using IdentityService.Domain;
using IdentityService.Infrastructure;
using IdentityService.WebApi.Applications.Dtos.Common;
using IM.Commons;
namespace IdentityService.WebApi.Applications.User
{
public class UserService
{
private readonly IIdRepository repository;
private readonly IMapper mapper;
private readonly UserDbContext userDb;
public UserService(IIdRepository repository, IMapper mapper,
UserDbContext userDbContext
)
{
this.repository = repository;
this.mapper = mapper;
userDb = userDbContext;
}
public async Task<Result<UserResponse?>> GetUserInfoAsync(Guid userId)
{
var user = await repository.FindByIdAsync(userId);
if (user is null)
{
return Result<UserResponse?>.Fail(ResultCode.USER_NOT_FOUND);
}
return Result<UserResponse?>.Success(mapper.Map<UserResponse>(user));
}
public async Task<Result<UserResponse>> UpdateAsync(UserUpdateCommand command)
{
var user = await repository.FindByIdAsync(command.UserId);
if (user is null)
{
return Result<UserResponse>.Fail(ResultCode.USER_NOT_FOUND);
}
user.Update(command.NickName, command.Region, command.Avatar, command.Description);
return Result<UserResponse>.Success(mapper.Map<UserResponse>(user));
}
public async Task<Result<List<UserResponse>>> GetUsersByIdsAsync(IEnumerable<Guid> ids)
{
var specification = new UserResponseFindSpecification(ids, mapper);
var users = await repository.GetUsersAsync(specification);
return Result<List<UserResponse>>.Success([.. users]);
}
}
}
@@ -0,0 +1,20 @@
namespace IdentityService.WebApi.Applications.User
{
public class UserUpdateCommand
{
public Guid UserId { get; private set; }
public string? NickName { get; private set; }
public string? Region { get; private set; }
public string? Avatar { get; private set; }
public string? Description { get; private set; }
public UserUpdateCommand(Guid userId, string? nickName, string? region, string? avatar, string? description)
{
UserId = userId;
NickName = nickName;
Region = region;
Avatar = avatar;
Description = description;
}
}
}