refactor: 重构用户与商品模块,统一业务模型与服务
1. 新增用户状态枚举UserStatusEnum,统一用户状态定义 2. 重构用户体系:合并WxUser与User实体为Users实体,统一用户管理 3. 新增微信小程序认证相关服务与控制器,实现一键登录功能 4. 新增商品管理完整服务与控制器,修复商品表字段映射问题 5. 删除冗余的WxUser相关服务与控制器代码 6. 新增Newtonsoft.Json依赖用于微信接口响应解析 7. 清理无用的文件夹引用配置
This commit is contained in:
160
QYZH.InteractiveMagazine.Service/WeChatAuthService.cs
Normal file
160
QYZH.InteractiveMagazine.Service/WeChatAuthService.cs
Normal file
@ -0,0 +1,160 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using QYZH.InteractiveMagazine.Common.Helpers;
|
||||
using QYZH.InteractiveMagazine.Infrastructure.Auth;
|
||||
using QYZH.InteractiveMagazine.Infrastructure.Cache;
|
||||
using QYZH.InteractiveMagazine.IService;
|
||||
using QYZH.InteractiveMagazine.IService.Dto;
|
||||
using QYZH.InteractiveMagazine.Models.Common;
|
||||
using QYZH.InteractiveMagazine.Models.Entity;
|
||||
using QYZH.InteractiveMagazine.Models.Settings;
|
||||
using QYZH.InteractiveMagazine.Repository;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序认证服务实现
|
||||
/// </summary>
|
||||
public class WeChatAuthService(BaseRepository<Users> usersRepository, IConfiguration configuration, ILogger<WeChatAuthService> logger) : BaseRepository<Users>, IWeChatAuthService
|
||||
{
|
||||
private const string TokenKeyPrefix = "InteractiveMagazine:WeChatAuth:Token";
|
||||
private const string Code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序一键登录
|
||||
/// </summary>
|
||||
/// <param name="input">登录输入(含微信 code)</param>
|
||||
/// <returns>登录结果(含 Token 和用户信息)</returns>
|
||||
public async Task<WeChatLoginOutput> LoginAsync(WeChatLoginInput input)
|
||||
{
|
||||
logger.LogInformation("微信小程序登录尝试");
|
||||
|
||||
// 参数校验
|
||||
if (string.IsNullOrWhiteSpace(input.Code))
|
||||
{
|
||||
throw new BusinessException("微信登录凭证 code 不能为空", 400);
|
||||
}
|
||||
|
||||
// 获取微信配置
|
||||
var weChatSettings = GetWeChatSettings();
|
||||
|
||||
// 调用微信 code2session 接口
|
||||
var wxResponse = await CallCode2SessionAsync(weChatSettings, input.Code);
|
||||
if (wxResponse == null || wxResponse.ErrCode != 0 || string.IsNullOrWhiteSpace(wxResponse.OpenId))
|
||||
{
|
||||
var errMsg = wxResponse?.ErrMsg ?? "未知错误";
|
||||
logger.LogWarning("微信 code2session 接口调用失败,errcode: {ErrCode}, errmsg: {ErrMsg}", wxResponse?.ErrCode, errMsg);
|
||||
throw new BusinessException($"微信登录失败:{errMsg}", 400);
|
||||
}
|
||||
|
||||
logger.LogInformation("微信 code2session 成功,OpenId: {OpenId}", wxResponse.OpenId);
|
||||
|
||||
// 查询用户是否已存在
|
||||
var user = await usersRepository.GetFirstAsync(u => u.OpenId == wxResponse.OpenId);
|
||||
var isNewUser = user == null;
|
||||
|
||||
if (isNewUser)
|
||||
{
|
||||
// 首次登录,创建新用户
|
||||
user = new Users
|
||||
{
|
||||
Name = $"wx_{wxResponse.OpenId[^8..]}",
|
||||
OpenId = wxResponse.OpenId,
|
||||
UnionId = wxResponse.UnionId,
|
||||
Type = "Normal",
|
||||
Status = "Active",
|
||||
GrowthPoints = 0,
|
||||
Points = 0
|
||||
};
|
||||
|
||||
var insertResult = await usersRepository.Insertable(user).ExecuteReturnIdentityAsync();
|
||||
if (insertResult <= 0)
|
||||
{
|
||||
logger.LogError("创建微信用户失败,OpenId: {OpenId}", wxResponse.OpenId);
|
||||
throw new BusinessException("创建用户失败,请稍后重试", 500);
|
||||
}
|
||||
|
||||
user.Id = insertResult;
|
||||
logger.LogInformation("微信新用户创建成功,UserId: {UserId}, OpenId: {OpenId}", user.Id, wxResponse.OpenId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 已有用户,校验状态
|
||||
if (user.Status == "Disabled")
|
||||
{
|
||||
logger.LogWarning("微信登录失败,用户已被禁用,UserId: {UserId}, OpenId: {OpenId}", user.Id, wxResponse.OpenId);
|
||||
throw new BusinessException("账号已被禁用,请联系客服", 403);
|
||||
}
|
||||
|
||||
logger.LogInformation("微信老用户登录,UserId: {UserId}, OpenId: {OpenId}", user.Id, wxResponse.OpenId);
|
||||
}
|
||||
|
||||
// 生成 JWT Token
|
||||
var jwtSettings = GetJwtSettings();
|
||||
var token = JwtHelper.GenerateToken((long)user.Id, user.Name, jwtSettings);
|
||||
|
||||
// 缓存 Token 到 Redis
|
||||
await RedisHelper.StringSetAsync($"{TokenKeyPrefix}:{user.Id}", token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes));
|
||||
|
||||
return new WeChatLoginOutput
|
||||
{
|
||||
Token = token,
|
||||
UserId = (long)user.Id,
|
||||
UserName = user.Name,
|
||||
OpenId = wxResponse.OpenId
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用微信 code2session 接口
|
||||
/// </summary>
|
||||
private async Task<WxCode2SessionResponse?> CallCode2SessionAsync(WeChatSettings settings, string code)
|
||||
{
|
||||
var url = string.Format(Code2SessionUrl, settings.AppId, settings.AppSecret, code);
|
||||
try
|
||||
{
|
||||
return await HttpHelper.GetAsync<WxCode2SessionResponse>(url);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "调用微信 code2session 接口异常,URL: {Url}", url);
|
||||
throw new BusinessException("微信服务请求失败,请稍后重试", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信配置
|
||||
/// </summary>
|
||||
private WeChatSettings GetWeChatSettings()
|
||||
{
|
||||
var settings = configuration.GetSection("WeChatSettings").Get<WeChatSettings>();
|
||||
if (settings == null || string.IsNullOrWhiteSpace(settings.AppId) || string.IsNullOrWhiteSpace(settings.AppSecret))
|
||||
{
|
||||
logger.LogError("微信配置不完整,请检查 appsettings.json 中的 WeChatSettings 节点");
|
||||
throw new BusinessException("微信配置不完整,请联系系统管理员", 500);
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 JWT 配置
|
||||
/// </summary>
|
||||
private JwtSettings GetJwtSettings()
|
||||
{
|
||||
var jwtSettings = configuration.GetSection("JwtSettings").Get<JwtSettings>()
|
||||
?? new JwtSettings
|
||||
{
|
||||
Issuer = "QYZH.InteractiveMagazine",
|
||||
Audience = "QYZH.InteractiveMagazine",
|
||||
SecretKey = "your-256-bit-secret-key-here-change-in-production",
|
||||
ExpiryMinutes = 120
|
||||
};
|
||||
|
||||
if (string.IsNullOrWhiteSpace(jwtSettings.SecretKey))
|
||||
{
|
||||
throw new BusinessException("JWT 配置不完整", 500);
|
||||
}
|
||||
|
||||
return jwtSettings;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user