小程序登录注册,工具类接口统一

This commit is contained in:
马梓彭 2026-03-30 21:39:00 +08:00
parent 16b000add2
commit 87a8c989bf
9 changed files with 215 additions and 706 deletions

View File

@ -2,54 +2,29 @@ using System.ComponentModel.DataAnnotations;
namespace YD_Event.Application.Client.Dtos;
public class WeChatLoginInput
/// <summary>
/// 小程序登录输入参数
/// </summary>
public class MiniProgramLoginInput
{
/// <summary>
/// 微信临时授权码
/// 手机号
/// </summary>
[Required(ErrorMessage = "code不能为空")]
public string Code { get; set; }
[Required(ErrorMessage = "手机号不能为空")]
[RegularExpression(@"^1[3456789]\d{9}$", ErrorMessage = "手机号格式不正确")]
public string Mobile { get; set; }
/// <summary>
/// 加密数据
/// 密码
/// </summary>
[Required(ErrorMessage = "encryptedData不能为空")]
public string EncryptedData { get; set; }
/// <summary>
/// 初始向量
/// </summary>
[Required(ErrorMessage = "iv不能为空")]
public string Iv { get; set; }
/// <summary>
/// 原始数据
/// </summary>
[Required(ErrorMessage = "rawData不能为空")]
public string RawData { get; set; }
/// <summary>
/// 签名
/// </summary>
[Required(ErrorMessage = "signature不能为空")]
public string Signature { get; set; }
public string Password { get; set; }
}
/// <summary>
/// 微信登录输出参数
/// 小程序登录输出参数
/// </summary>
public class WeChatLoginOutput
public class MiniProgramLoginOutput
{
/// <summary>
/// OpenId
/// </summary>
public string Openid { get; set; }
/// <summary>
/// 会话密钥
/// </summary>
public string SessionKey { get; set; }
/// <summary>
/// 访问令牌
/// </summary>
@ -61,7 +36,7 @@ public class WeChatLoginOutput
public string RefreshToken { get; set; }
/// <summary>
/// 过期时间
/// 过期时间(秒)
/// </summary>
public int ExpiresIn { get; set; }
@ -72,50 +47,47 @@ public class WeChatLoginOutput
}
/// <summary>
/// 微信注册输入参数
/// 小程序注册输入参数
/// </summary>
public class WeChatRegisterInput
public class MiniProgramRegisterInput
{
/// <summary>
/// OpenId
/// 手机号(必填)
/// </summary>
[Required(ErrorMessage = "openid不能为空")]
public string Openid { get; set; }
[Required(ErrorMessage = "手机号不能为空")]
[RegularExpression(@"^1[3456789]\d{9}$", ErrorMessage = "手机号格式不正确")]
public string Mobile { get; set; }
/// <summary>
/// 加密数据
/// 密码(必填)
/// </summary>
[Required(ErrorMessage = "encryptedData不能为空")]
public string EncryptedData { get; set; }
[Required(ErrorMessage = "密码不能为空")]
[StringLength(32, MinimumLength = 6, ErrorMessage = "密码长度必须在6-32位之间")]
public string Password { get; set; }
/// <summary>
/// 初始向量
/// 验证码(必填)
/// </summary>
[Required(ErrorMessage = "iv不能为空")]
public string Iv { get; set; }
[Required(ErrorMessage = "验证码不能为空")]
public string VerificationCode { get; set; }
/// <summary>
/// 原始数据
/// 昵称(可选)
/// </summary>
[Required(ErrorMessage = "rawData不能为空")]
public string RawData { get; set; }
[StringLength(64, ErrorMessage = "昵称长度不能超过64个字符")]
public string NickName { get; set; }
/// <summary>
/// 签名
/// 头像(可选)
/// </summary>
[Required(ErrorMessage = "signature不能为空")]
public string Signature { get; set; }
/// <summary>
/// 邀请码 (可选)
/// </summary>
public string? InviteCode { get; set; }
[StringLength(512, ErrorMessage = "头像URL长度不能超过512个字符")]
public string Avatar { get; set; }
}
/// <summary>
/// 微信注册输出参数
/// 小程序注册输出参数
/// </summary>
public class WeChatRegisterOutput
public class MiniProgramRegisterOutput
{
/// <summary>
/// 用户ID
@ -123,14 +95,14 @@ public class WeChatRegisterOutput
public long UserId { get; set; }
/// <summary>
/// 昵称
/// 手机号
/// </summary>
public string Nickname { get; set; }
public string Mobile { get; set; }
/// <summary>
/// 头像URL
/// 昵称
/// </summary>
public string AvatarUrl { get; set; }
public string NickName { get; set; }
/// <summary>
/// 注册时间
@ -139,123 +111,27 @@ public class WeChatRegisterOutput
}
/// <summary>
/// 微信重置密码输入参数
/// 小程序重置密码输入参数
/// </summary>
public class WeChatResetPasswordInput
public class MiniProgramResetPasswordInput
{
/// <summary>
/// OpenId
/// 手机号(必填)
/// </summary>
[Required(ErrorMessage = "openid不能为空")]
public string Openid { get; set; }
[Required(ErrorMessage = "手机号不能为空")]
[RegularExpression(@"^1[3456789]\d{9}$", ErrorMessage = "手机号格式不正确")]
public string Mobile { get; set; }
/// <summary>
/// 加密数据
/// 新密码(必填)
/// </summary>
[Required(ErrorMessage = "encryptedData不能为空")]
public string EncryptedData { get; set; }
[Required(ErrorMessage = "新密码不能为空")]
[StringLength(32, MinimumLength = 6, ErrorMessage = "密码长度必须在6-32位之间")]
public string NewPassword { get; set; }
/// <summary>
/// 初始向量
/// 验证码(必填)
/// </summary>
[Required(ErrorMessage = "iv不能为空")]
public string Iv { get; set; }
/// <summary>
/// 邮箱 (可选)
/// </summary>
public string? Email { get; set; }
/// <summary>
/// 短信验证码 (可选)
/// </summary>
public string? SmsCode { get; set; }
}
/// <summary>
/// 微信重置密码输出参数
/// </summary>
public class WeChatResetPasswordOutput
{
/// <summary>
/// 重置令牌
/// </summary>
public string ResetToken { get; set; }
/// <summary>
/// 过期时间
/// </summary>
public DateTime ExpireTime { get; set; }
/// <summary>
/// 发送渠道 (email/sms)
/// </summary>
public string SendChannel { get; set; }
}
/// <summary>
/// 微信用户信息
/// </summary>
public class WeChatUserInfo
{
/// <summary>
/// OpenId
/// </summary>
public string OpenId { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string NickName { get; set; }
/// <summary>
/// 性别
/// </summary>
public int Gender { get; set; }
/// <summary>
/// 城市
/// </summary>
public string City { get; set; }
/// <summary>
/// 省份
/// </summary>
public string Province { get; set; }
/// <summary>
/// 国家
/// </summary>
public string Country { get; set; }
/// <summary>
/// 头像URL
/// </summary>
public string AvatarUrl { get; set; }
/// <summary>
/// UnionId
/// </summary>
public string UnionId { get; set; }
/// <summary>
/// 水印
/// </summary>
public Watermark Watermark { get; set; }
}
/// <summary>
/// 水印信息
/// </summary>
public class Watermark
{
/// <summary>
/// 时间戳
/// </summary>
public long Timestamp { get; set; }
/// <summary>
/// AppId
/// </summary>
public string Appid { get; set; }
[Required(ErrorMessage = "验证码不能为空")]
public string VerificationCode { get; set; }
}

View File

@ -1,13 +1,6 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using System.Security.Cryptography;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using YD_Event.Application.Client.Dtos;
using YD_Event.Core.Infrastructure.WeChat;
using YD_Event.Application.Auth;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
namespace YD_Event.Application.Client;
@ -17,33 +10,21 @@ namespace YD_Event.Application.Client;
[ApiDescriptionSettings("微信小程序接口")]
public class OAuthController : IDynamicApiController
{
private readonly WeChatService _weChatTool;
private readonly ISqlSugarRepository<AuthAccount> _accountRepository;
private readonly ISqlSugarRepository<YD_Event.Core.Entities.AppUser> _appUserRepository;
private readonly ISqlSugarRepository<SysRole> _roleRepository;
private readonly ISqlSugarRepository<SysUserRole> _userRoleRepository;
private readonly IEasyCachingProvider _easyCachingProvider;
private readonly IMemoryCache _memoryCache;
private readonly IIdGenerator _idGenerator;
private readonly ILogger<OAuthController> _logger;
private const string SessionKeyCachePrefix = "wechat_session_";
private const string SmsCodeCachePrefix = "sms:code:";
public OAuthController(
WeChatService weChatTool,
ISqlSugarRepository<AuthAccount> accountRepository,
ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository,
ISqlSugarRepository<SysRole> roleRepository,
ISqlSugarRepository<SysUserRole> userRoleRepository,
IEasyCachingProvider easyCachingProvider,
IMemoryCache memoryCache,
IIdGenerator idGenerator,
ILogger<OAuthController> logger)
{
_weChatTool = weChatTool;
_accountRepository = accountRepository;
_appUserRepository = appUserRepository;
_roleRepository = roleRepository;
_userRoleRepository = userRoleRepository;
_easyCachingProvider = easyCachingProvider;
_memoryCache = memoryCache;
_idGenerator = idGenerator;
_logger = logger;
}
@ -55,52 +36,59 @@ public class OAuthController : IDynamicApiController
/// <returns></returns>
[HttpPost("login")]
[AllowAnonymous]
public async Task<WeChatLoginOutput> Login([FromBody] WeChatLoginInput input)
public async Task<MiniProgramLoginOutput> Login([FromBody] MiniProgramLoginInput input)
{
// 1. code2Session
var sessionResult = await _weChatTool.Code2Session(input.Code);
string openid = sessionResult.OpenId;
string sessionKey = sessionResult.SessionKey;
// 缓存 session_key,用于后续解密
await _easyCachingProvider.SetAsync($"{SessionKeyCachePrefix}{openid}", sessionKey, TimeSpan.FromHours(2));
// 2. 校验签名 (可选,根据业务严谨性)
// var signature2 = Hash(input.RawData + sessionKey);
// if (signature2 != input.Signature) throw Oops.Bah("签名校验失败");
// 3. 查找用户
var account = await _accountRepository.GetFirstAsync(x => x.OAuthId == openid && x.Type == "WeChat");
string accessToken = null;
string refreshToken = null;
object userInfo = null;
int expiresIn = 7200;
if (account != null)
if (string.IsNullOrEmpty(input.Password) && string.IsNullOrEmpty(input.VerificationCode))
{
// 生成 Token
(accessToken, refreshToken) = GenerateTokens(account);
// 获取用户信息
var appUser = await _appUserRepository.GetFirstAsync(x => x.UserId == account.Id);
if (appUser != null)
throw Oops.Bah("密码和验证码至少提供一个");
}
var appUser = await _appUserRepository.GetFirstAsync(x => x.Mobile == input.Mobile);
if (appUser == null)
{
throw Oops.Bah("用户不存在,请先注册");
}
if (!string.IsNullOrEmpty(input.Password))
{
if (string.IsNullOrEmpty(appUser.Password))
{
userInfo = new { appUser.Name, appUser.Id, appUser.Mobile, appUser.Avatar, appUser.NickName };
throw Oops.Bah("该用户未设置密码,请使用验证码登录");
}
else
var encryptedPassword = MD5Encryption.Encrypt($"{_idGenerator.Encode(appUser.Id)}{input.Password}");
if (appUser.Password != encryptedPassword)
{
userInfo = new { account.Name, account.Avatar };
throw Oops.Bah("密码错误");
}
}
return new WeChatLoginOutput
if (!string.IsNullOrEmpty(input.VerificationCode))
{
var cacheKey = $"{SmsCodeCachePrefix}{input.Mobile}";
string cachedCode = null;
if (!_memoryCache.TryGetValue(cacheKey, out cachedCode) || cachedCode != input.VerificationCode)
{
throw Oops.Bah("验证码错误或已过期");
}
_memoryCache.Remove(cacheKey);
}
(string accessToken, string refreshToken) = GenerateTokens(appUser);
var userInfo = new
{
appUser.Name,
appUser.Id,
appUser.Mobile,
appUser.Avatar,
appUser.NickName
};
return new MiniProgramLoginOutput
{
Openid = openid,
SessionKey = sessionKey, // 需求要求返回
AccessToken = accessToken,
RefreshToken = refreshToken,
ExpiresIn = expiresIn,
ExpiresIn = 7200,
UserInfo = userInfo
};
}
@ -113,204 +101,95 @@ public class OAuthController : IDynamicApiController
[HttpPost("register")]
[AllowAnonymous]
[UnitOfWork]
public async Task<WeChatRegisterOutput> Register([FromBody] WeChatRegisterInput input)
public async Task<MiniProgramRegisterOutput> Register([FromBody] MiniProgramRegisterInput input)
{
// 1. 获取 session_key
var cacheKey = $"{SessionKeyCachePrefix}{input.Openid}";
var sessionKeyCache = await _easyCachingProvider.GetAsync<string>(cacheKey);
if (!sessionKeyCache.HasValue) throw Oops.Bah("SessionKey已过期,请重新登录");
string sessionKey = sessionKeyCache.Value;
// 2. 解密用户信息
string json = DecryptWeChatData(input.EncryptedData, sessionKey, input.Iv);
var wxUser = JsonConvert.DeserializeObject<WeChatUserInfo>(json);
if (wxUser == null) throw Oops.Bah("解密用户信息失败");
// 验证 watermark
var configAppId = App.Configuration["WeChat:AppId"];
if (!string.IsNullOrEmpty(configAppId) && wxUser.Watermark?.Appid != configAppId)
var cacheKey = $"{SmsCodeCachePrefix}{input.Mobile}";
string cachedCode = null;
if (!_memoryCache.TryGetValue(cacheKey, out cachedCode) || cachedCode != input.VerificationCode)
{
// 仅记录警告,防止配置不一致导致注册失败
_logger.LogWarning($"Watermark AppId mismatch: {wxUser.Watermark?.Appid} vs {configAppId}");
throw Oops.Bah("验证码错误或已过期");
}
_memoryCache.Remove(cacheKey);
if (await _appUserRepository.IsAnyAsync(x => x.Mobile == input.Mobile))
{
throw Oops.Bah("该手机号已注册");
}
// 3. 写入 AuthAccount
// 检查是否已存在
if (await _accountRepository.IsAnyAsync(x => x.OAuthId == input.Openid && x.Type == "WeChat"))
{
throw Oops.Bah("该用户已注册");
}
long accountId = _idGenerator.NewLong();
var account = new AuthAccount
{
Id = accountId,
OAuthId = input.Openid,
Type = "WeChat",
Name = wxUser.NickName,
Avatar = wxUser.AvatarUrl,
Gender = (Gender)wxUser.Gender, // 假设 Gender 枚举兼容
CreatedTime = DateTime.Now,
CreatedUserId = accountId // 自指
};
await _accountRepository.InsertAsync(account);
// 4. 写入 AppUser (Profile)
long appUserId = _idGenerator.NewLong();
var encryptedPassword = MD5Encryption.Encrypt($"{_idGenerator.Encode(appUserId)}{input.Password}");
var appUser = new YD_Event.Core.Entities.AppUser
{
Id = appUserId,
UserId = accountId,
Name = wxUser.NickName,
NickName = wxUser.NickName,
Avatar = wxUser.AvatarUrl,
Gender = (Gender)wxUser.Gender,
PersonType = PersonType.User, // 普通用户
Name = input.NickName ?? input.Mobile,
NickName = input.NickName,
Avatar = input.Avatar,
Gender = Gender.Unknown,
Mobile = input.Mobile,
Password = encryptedPassword,
PersonType = PersonType.User,
Status = AvailabilityStatus.Enable,
AuditStatus = AuditStatus.Pass,
CreatedTime = DateTime.Now,
CreatedUserId = accountId
CreatedUserId = appUserId
};
await _appUserRepository.InsertAsync(appUser);
// 5. 初始化默认角色
// 查找默认角色,假设为 "OrdinaryUser" 或 "User"
var defaultRole = await _roleRepository.GetFirstAsync(x => x.Code == "User" || x.Code == "OrdinaryUser");
if (defaultRole == null)
return new MiniProgramRegisterOutput
{
// 如果不存在,创建一个默认角色
defaultRole = new SysRole
{
Id = _idGenerator.NewLong(),
Name = "普通用户",
Code = "User",
Status = AvailabilityStatus.Enable,
CreatedTime = DateTime.Now
};
await _roleRepository.InsertAsync(defaultRole);
}
// 绑定角色 (这里是 AppUser 还是 AuthAccount 绑定角色? SysUserRole 关联 UserId,通常指 AuthAccount.Id 或 SysUser.Id)
// 假设 SysUserRole.UserId 对应 AuthAccount.Id (因为 AuthAccount 是登录主体)
await _userRoleRepository.InsertAsync(new SysUserRole
{
Id = _idGenerator.NewLong(),
UserId = accountId,
RoleId = defaultRole.Id,
CreatedTime = DateTime.Now
});
return new WeChatRegisterOutput
{
UserId = accountId,
Nickname = account.Name,
AvatarUrl = account.Avatar,
RegisterTime = account.CreatedTime
UserId = appUser.Id,
Mobile = appUser.Mobile,
NickName = appUser.NickName,
RegisterTime = appUser.CreatedTime
};
}
/// <summary>
/// 找回密码接口
/// 重置密码接口
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("reset-password")]
[AllowAnonymous]
public async Task<WeChatResetPasswordOutput> ResetPassword([FromBody] WeChatResetPasswordInput input)
public async Task ResetPassword([FromBody] MiniProgramResetPasswordInput input)
{
// 1. 获取 session_key
var cacheKey = $"{SessionKeyCachePrefix}{input.Openid}";
var sessionKeyCache = await _easyCachingProvider.GetAsync<string>(cacheKey);
if (!sessionKeyCache.HasValue) throw Oops.Bah("SessionKey已过期,请重新登录");
string sessionKey = sessionKeyCache.Value;
// 2. 验证微信身份 (尝试解密)
try
var cacheKey = $"{SmsCodeCachePrefix}{input.Mobile}";
string cachedCode = null;
if (!_memoryCache.TryGetValue(cacheKey, out cachedCode) || cachedCode != input.VerificationCode)
{
string json = DecryptWeChatData(input.EncryptedData, sessionKey, input.Iv);
var wxUser = JsonConvert.DeserializeObject<WeChatUserInfo>(json);
if (wxUser.OpenId != input.Openid) throw Oops.Bah("身份验证失败: OpenId不匹配");
throw Oops.Bah("验证码错误或已过期");
}
catch (Exception ex)
_memoryCache.Remove(cacheKey);
var appUser = await _appUserRepository.GetFirstAsync(x => x.Mobile == input.Mobile);
if (appUser == null)
{
_logger.LogError(ex, "ResetPassword Decrypt Failed");
throw Oops.Bah("身份验证失败");
throw Oops.Bah("用户不存在");
}
// 3. 生成一次性 Token
string resetToken = Guid.NewGuid().ToString("N");
// 4. 发送邮件/短信 (Mock)
string sendChannel = "none";
if (!string.IsNullOrEmpty(input.Email))
{
// Mock send email
_logger.LogInformation($"Send Reset Token {resetToken} to Email {input.Email}");
sendChannel = "email";
}
else if (!string.IsNullOrEmpty(input.SmsCode))
{
// Verify Sms Code (Mock)
// Mock send sms
_logger.LogInformation($"Verify SMS Code {input.SmsCode} and generate token");
sendChannel = "sms";
}
var encryptedPassword = MD5Encryption.Encrypt($"{_idGenerator.Encode(appUser.Id)}{input.NewPassword}");
appUser.Password = encryptedPassword;
appUser.UpdatedTime = DateTime.Now;
appUser.UpdatedUserId = appUser.Id;
return new WeChatResetPasswordOutput
{
ResetToken = resetToken,
ExpireTime = DateTime.Now.AddMinutes(15),
SendChannel = sendChannel
};
}
/// <summary>
/// AES-128-CBC 解密
/// </summary>
private string DecryptWeChatData(string encryptedData, string sessionKey, string iv)
{
try
{
byte[] encryptedBytes = Convert.FromBase64String(encryptedData);
byte[] keyBytes = Convert.FromBase64String(sessionKey);
byte[] ivBytes = Convert.FromBase64String(iv);
using var aes = Aes.Create();
aes.KeySize = 128;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = keyBytes;
aes.IV = ivBytes;
using var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using var ms = new MemoryStream(encryptedBytes);
using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
using var sr = new StreamReader(cs);
return sr.ReadToEnd();
}
catch (Exception ex)
{
_logger.LogError(ex, "AES Decrypt Error");
throw Oops.Bah("数据解密失败");
}
await _appUserRepository.UpdateAsync(appUser);
}
/// <summary>
/// 生成自定义 Token
/// </summary>
private (string AccessToken, string RefreshToken) GenerateTokens(AuthAccount account)
private (string AccessToken, string RefreshToken) GenerateTokens(YD_Event.Core.Entities.AppUser appUser)
{
long uniqueId = _idGenerator.NewLong();
string accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>()
{
[AuthClaimsConst.AuthIdKey] = account.Id,
[AuthClaimsConst.AccountKey] = account.OAuthId,
[AuthClaimsConst.AuthIdKey] = appUser.Id,
[AuthClaimsConst.AccountKey] = appUser.Mobile,
[AuthClaimsConst.UuidKey] = uniqueId,
[AuthClaimsConst.AuthPlatformTypeKey] = AuthPlatformType.WeChatApplet
});
// 获取刷新 token
string refreshToken = JWTEncryption.GenerateRefreshToken(accessToken);
return (accessToken, refreshToken);

View File

@ -8,6 +8,4 @@ public class SendVerificationCodeInput
[Required(ErrorMessage = "手机号不能为空")]
[RegularExpression(@"^1[3456789]\d{9}$", ErrorMessage = "手机号格式不正确")]
public string Phone { get; set; } = null!;
public string? Code { get; set; }
}

View File

@ -16,7 +16,7 @@ public class SmsService : IDynamicApiController, ITransient
_memoryCache = memoryCache;
}
[HttpPost("sms/sendVerificationCode")]
[HttpPost("sendVerificationCode")]
[DisplayName("发送短信验证码")]
[AllowAnonymous]
public async Task SendVerificationCode([FromBody] SendVerificationCodeInput input)
@ -27,7 +27,7 @@ public class SmsService : IDynamicApiController, ITransient
throw Oops.Bah("发送太频繁,请稍后再试");
}
string code = input.Code ?? new Random().Next(100000, 999999).ToString();
string code = new Random().Next(100000, 999999).ToString();
await _smsService.SendVerificationCode(input.Phone, code);

View File

@ -360,7 +360,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
Gender = member.Gender,
IdCard = member.IdCardNumber,
Phone = member.Mobile,
Age = member.Age,
Age = member.Age ?? 0,
BirthDate = member.BirthDate ?? DateTime.MinValue,
PersonType = PersonType.Athlete,
CreatedUserId = userId,

View File

@ -2080,239 +2080,124 @@
拒绝/取消原因
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginInput.Code">
<member name="T:YD_Event.Application.Client.Dtos.MiniProgramLoginInput">
<summary>
微信临时授权码
小程序登录输入参数
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginInput.EncryptedData">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramLoginInput.Mobile">
<summary>
加密数据
手机号
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginInput.Iv">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramLoginInput.Password">
<summary>
初始向量
密码(可选,与验证码至少提供一个)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginInput.RawData">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramLoginInput.VerificationCode">
<summary>
原始数据
验证码(可选,与密码至少提供一个)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginInput.Signature">
<member name="T:YD_Event.Application.Client.Dtos.MiniProgramLoginOutput">
<summary>
签名
小程序登录输出参数
</summary>
</member>
<member name="T:YD_Event.Application.Client.Dtos.WeChatLoginOutput">
<summary>
微信登录输出参数
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginOutput.Openid">
<summary>
OpenId
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginOutput.SessionKey">
<summary>
会话密钥
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginOutput.AccessToken">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramLoginOutput.AccessToken">
<summary>
访问令牌
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginOutput.RefreshToken">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramLoginOutput.RefreshToken">
<summary>
刷新令牌
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginOutput.ExpiresIn">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramLoginOutput.ExpiresIn">
<summary>
过期时间
过期时间(秒)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatLoginOutput.UserInfo">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramLoginOutput.UserInfo">
<summary>
用户信息
</summary>
</member>
<member name="T:YD_Event.Application.Client.Dtos.WeChatRegisterInput">
<member name="T:YD_Event.Application.Client.Dtos.MiniProgramRegisterInput">
<summary>
微信注册输入参数
小程序注册输入参数
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterInput.Openid">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterInput.Mobile">
<summary>
OpenId
手机号(必填)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterInput.EncryptedData">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterInput.Password">
<summary>
加密数据
密码(必填)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterInput.Iv">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterInput.VerificationCode">
<summary>
初始向量
验证码(必填)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterInput.RawData">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterInput.NickName">
<summary>
原始数据
昵称(可选)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterInput.Signature">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterInput.Avatar">
<summary>
签名
头像(可选)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterInput.InviteCode">
<member name="T:YD_Event.Application.Client.Dtos.MiniProgramRegisterOutput">
<summary>
邀请码 (可选)
小程序注册输出参数
</summary>
</member>
<member name="T:YD_Event.Application.Client.Dtos.WeChatRegisterOutput">
<summary>
微信注册输出参数
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterOutput.UserId">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterOutput.UserId">
<summary>
用户ID
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterOutput.Nickname">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterOutput.Mobile">
<summary>
手机号
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterOutput.NickName">
<summary>
昵称
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterOutput.AvatarUrl">
<summary>
头像URL
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatRegisterOutput.RegisterTime">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramRegisterOutput.RegisterTime">
<summary>
注册时间
</summary>
</member>
<member name="T:YD_Event.Application.Client.Dtos.WeChatResetPasswordInput">
<member name="T:YD_Event.Application.Client.Dtos.MiniProgramResetPasswordInput">
<summary>
微信重置密码输入参数
小程序重置密码输入参数
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatResetPasswordInput.Openid">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramResetPasswordInput.Mobile">
<summary>
OpenId
手机号(必填)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatResetPasswordInput.EncryptedData">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramResetPasswordInput.NewPassword">
<summary>
加密数据
新密码(必填)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatResetPasswordInput.Iv">
<member name="P:YD_Event.Application.Client.Dtos.MiniProgramResetPasswordInput.VerificationCode">
<summary>
初始向量
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatResetPasswordInput.Email">
<summary>
邮箱 (可选)
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatResetPasswordInput.SmsCode">
<summary>
短信验证码 (可选)
</summary>
</member>
<member name="T:YD_Event.Application.Client.Dtos.WeChatResetPasswordOutput">
<summary>
微信重置密码输出参数
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatResetPasswordOutput.ResetToken">
<summary>
重置令牌
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatResetPasswordOutput.ExpireTime">
<summary>
过期时间
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatResetPasswordOutput.SendChannel">
<summary>
发送渠道 (email/sms)
</summary>
</member>
<member name="T:YD_Event.Application.Client.Dtos.WeChatUserInfo">
<summary>
微信用户信息
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.OpenId">
<summary>
OpenId
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.NickName">
<summary>
昵称
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.Gender">
<summary>
性别
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.City">
<summary>
城市
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.Province">
<summary>
省份
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.Country">
<summary>
国家
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.AvatarUrl">
<summary>
头像URL
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.UnionId">
<summary>
UnionId
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.WeChatUserInfo.Watermark">
<summary>
水印
</summary>
</member>
<member name="T:YD_Event.Application.Client.Dtos.Watermark">
<summary>
水印信息
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.Watermark.Timestamp">
<summary>
时间戳
</summary>
</member>
<member name="P:YD_Event.Application.Client.Dtos.Watermark.Appid">
<summary>
AppId
验证码(必填)
</summary>
</member>
<member name="T:YD_Event.Application.Client.Dtos.MyPageInput">
@ -2719,33 +2604,28 @@
微信小程序认证接口
</summary>
</member>
<member name="M:YD_Event.Application.Client.OAuthController.Login(YD_Event.Application.Client.Dtos.WeChatLoginInput)">
<member name="M:YD_Event.Application.Client.OAuthController.Login(YD_Event.Application.Client.Dtos.MiniProgramLoginInput)">
<summary>
登录接口
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:YD_Event.Application.Client.OAuthController.Register(YD_Event.Application.Client.Dtos.WeChatRegisterInput)">
<member name="M:YD_Event.Application.Client.OAuthController.Register(YD_Event.Application.Client.Dtos.MiniProgramRegisterInput)">
<summary>
注册接口
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:YD_Event.Application.Client.OAuthController.ResetPassword(YD_Event.Application.Client.Dtos.WeChatResetPasswordInput)">
<member name="M:YD_Event.Application.Client.OAuthController.ResetPassword(YD_Event.Application.Client.Dtos.MiniProgramResetPasswordInput)">
<summary>
找回密码接口
重置密码接口
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:YD_Event.Application.Client.OAuthController.DecryptWeChatData(System.String,System.String,System.String)">
<summary>
AES-128-CBC 解密
</summary>
</member>
<member name="M:YD_Event.Application.Client.OAuthController.GenerateTokens(YD_Event.Core.Entities.AuthAccount)">
<member name="M:YD_Event.Application.Client.OAuthController.GenerateTokens(YD_Event.Core.Entities.AppUser)">
<summary>
生成自定义 Token
</summary>

View File

@ -52,8 +52,8 @@ public class AppUser : Entity<long>, ISoftDelete, ICreatedUserId, ICreatedTime,
/// <summary>
/// 姓名
/// </summary>
[SugarColumn(Length = 64)]
public string Name { get; set; }
[SugarColumn(Length = 64, IsNullable = true)]
public string? Name { get; set; }
/// <summary>
/// 性别
@ -63,7 +63,8 @@ public class AppUser : Entity<long>, ISoftDelete, ICreatedUserId, ICreatedTime,
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
[SugarColumn(IsNullable = true)]
public int? Age { get; set; }
/// <summary>
/// 出生日期
@ -75,18 +76,24 @@ public class AppUser : Entity<long>, ISoftDelete, ICreatedUserId, ICreatedTime,
/// 联系电话
/// </summary>
[SugarColumn(Length = 20)]
public string Mobile { get; set; }
public string Mobile { get; set; } = null!;
/// <summary>
/// 密码(用于登录)
/// </summary>
[SugarColumn(Length = 64, IsNullable = true)]
public string? Password { get; set; }
/// <summary>
/// 身份证号码
/// </summary>
[SugarColumn(Length = 20)]
public string IdCardNumber { get; set; }
[SugarColumn(Length = 20, IsNullable = true)]
public string? IdCardNumber { get; set; }
/// <summary>
/// 身份证图片URL
/// </summary>
[SugarColumn(Length = 512)]
[SugarColumn(Length = 512, IsNullable = true)]
public string? IdCardImageUrl { get; set; }
/// <summary>

View File

@ -1,71 +0,0 @@
using YD_Event.Core.Enum;
namespace YD_Event.Core.Entities;
/// <summary>
/// 博客授权用户
/// </summary>
public class AuthAccount : Entity<long>, ISoftDelete, ICreatedUserId, ICreatedTime, IUpdatedUserId, IUpdatedTime
{
/// <summary>
/// 授权唯一标识
/// </summary>
public string OAuthId { get; set; }
/// <summary>
/// 授权类型
/// </summary>
public string Type { get; set; }
/// <summary>
/// 博主标识
/// </summary>
public bool IsBlogger { get; set; }
/// <summary>
/// 姓名(昵称)
/// </summary>
[SugarColumn(Length = 64)]
public string? Name { get; set; }
/// <summary>
/// 性别
/// </summary>
public Gender Gender { get; set; }
/// <summary>
/// 头像
/// </summary>
[SugarColumn(Length = 256)]
public string? Avatar { get; set; }
/// <summary>
/// 邮箱
/// </summary>
[SugarColumn(Length = 128)]
public string? Email { get; set; }
/// <summary>
/// 标记删除
/// </summary>
public bool DeleteMark { get; set; }
/// <summary>
/// 创建人
/// </summary>
public long CreatedUserId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedTime { get; set; }
/// <summary>
/// 更新人
/// </summary>
public long? UpdatedUserId { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdatedTime { get; set; }
}

View File

@ -509,6 +509,11 @@
联系电话
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AppUser.Password">
<summary>
密码(用于登录)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AppUser.IdCardNumber">
<summary>
身份证号码
@ -564,71 +569,6 @@
更新时间
</summary>
</member>
<member name="T:YD_Event.Core.Entities.AuthAccount">
<summary>
博客授权用户
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.OAuthId">
<summary>
授权唯一标识
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.Type">
<summary>
授权类型
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.IsBlogger">
<summary>
博主标识
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.Name">
<summary>
姓名(昵称)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.Gender">
<summary>
性别
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.Avatar">
<summary>
头像
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.Email">
<summary>
邮箱
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.DeleteMark">
<summary>
标记删除
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.CreatedUserId">
<summary>
创建人
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.CreatedTime">
<summary>
创建时间
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.UpdatedUserId">
<summary>
更新人
</summary>
</member>
<member name="P:YD_Event.Core.Entities.AuthAccount.UpdatedTime">
<summary>
更新时间
</summary>
</member>
<member name="T:YD_Event.Core.Entities.Banner">
<summary>
轮播图配置