提交代码
This commit is contained in:
parent
98f4214809
commit
af397d25c8
|
|
@ -4,6 +4,7 @@ using ChouBox.Code.TencentCloudExtend.Model;
|
|||
using ChouBox.Model.Entities;
|
||||
|
||||
using HuanMeng.DotNetCore.Base;
|
||||
using HuanMeng.DotNetCore.Extensions;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
|
@ -89,10 +90,66 @@ public class ChouBoxCodeBase
|
|||
if (_httpContextAccessor == null)
|
||||
{
|
||||
_httpContextAccessor = _serviceProvider.GetRequiredService<IHttpContextAccessor>();
|
||||
|
||||
}
|
||||
return _httpContextAccessor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取客户端真实IP地址,考虑Nginx等代理情况
|
||||
/// </summary>
|
||||
/// <returns>客户端真实IP地址</returns>
|
||||
protected string GetRealIpAddress()
|
||||
{
|
||||
var context = HttpContextAccessor.HttpContext;
|
||||
if (context == null)
|
||||
return "unknown";
|
||||
|
||||
// 尝试从X-Forwarded-For获取真实IP
|
||||
string ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||
|
||||
// 如果X-Forwarded-For为空,尝试X-Real-IP
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Request.Headers["X-Real-IP"].FirstOrDefault();
|
||||
}
|
||||
|
||||
// 尝试其他可能包含真实IP的头
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Request.Headers["Proxy-Client-IP"].FirstOrDefault();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Request.Headers["WL-Proxy-Client-IP"].FirstOrDefault();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Request.Headers["HTTP_CLIENT_IP"].FirstOrDefault();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Request.Headers["HTTP_X_FORWARDED_FOR"].FirstOrDefault();
|
||||
}
|
||||
|
||||
// 如果还是获取不到,则使用RemoteIpAddress
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Connection.RemoteIpAddress?.ToString();
|
||||
}
|
||||
|
||||
// 如果X-Forwarded-For包含多个IP,取第一个非内网IP
|
||||
if (!string.IsNullOrEmpty(ip) && ip.Contains(","))
|
||||
{
|
||||
ip = ip.Split(',')[0].Trim();
|
||||
}
|
||||
|
||||
return ip ?? "unknown";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 日志
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
using ChouBox.Code.AppExtend;
|
||||
using ChouBox.Code.TencentCloudExtend;
|
||||
using ChouBox.Model.Entities;
|
||||
|
||||
using HuanMeng.DotNetCore.Base;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -16,17 +21,23 @@ namespace ChouBox.Code.Other;
|
|||
/// </summary>
|
||||
public class SMSBLL : ChouBoxCodeBase
|
||||
{
|
||||
private const string RETRY_COUNT_SUFFIX = ":RetryCount";
|
||||
private const string LOCK_SUFFIX = ":Lock";
|
||||
|
||||
public SMSBLL(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送验证码
|
||||
/// </summary>
|
||||
/// <param name="phone"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <param name="codeType">验证码类型:1-注册,2-登录,3-找回密码,4-修改手机,5-修改邮箱,6-其他</param>
|
||||
/// <param name="userId">用户ID,可为空表示未登录用户</param>
|
||||
/// <returns>返回下一次可请求的等待秒数,-1表示当天不能再请求</returns>
|
||||
/// <exception cref="CustomException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task<string> SendPhoneAsync(string phone)
|
||||
public async Task<int> SendPhoneAsync(string phone, sbyte codeType = 2, ulong? userId = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(phone))
|
||||
{
|
||||
|
|
@ -37,23 +48,131 @@ public class SMSBLL : ChouBoxCodeBase
|
|||
{
|
||||
throw new ArgumentNullException("暂未开放发送验证码!");
|
||||
}
|
||||
|
||||
// 检查当天发送次数限制
|
||||
var dailyCountKey = $"VerificationCodeDailyCount:{phone}:{DateTime.Now:yyyyMMdd}";
|
||||
var dailyCount = RedisCache.StringGet<int?>(dailyCountKey) ?? 0;
|
||||
|
||||
|
||||
|
||||
// 获取重试次数
|
||||
var retryCountKey = $"VerificationCode:{phone}{RETRY_COUNT_SUFFIX}";
|
||||
var retryCount = RedisCache.StringGet<int?>(retryCountKey) ?? 0;
|
||||
var resendLockKey = $"VerificationCode:{phone}{LOCK_SUFFIX}";
|
||||
var resendLock = RedisCache.StringGet<string>(resendLockKey);
|
||||
|
||||
// 计算本次等待时间
|
||||
int waitSeconds = GetWaitSeconds(retryCount);
|
||||
|
||||
if (resendLock != null && !string.IsNullOrEmpty(resendLock))
|
||||
{
|
||||
// 获取锁的剩余过期时间(秒)
|
||||
var remainingSeconds = RedisCache.KeyTimeToLive(resendLockKey)?.TotalSeconds ?? 0;
|
||||
remainingSeconds = Math.Ceiling(remainingSeconds); // 向上取整
|
||||
|
||||
string message;
|
||||
if (remainingSeconds <= 60)
|
||||
{
|
||||
message = $"验证码发送过于频繁,请{remainingSeconds}秒后再试。";
|
||||
}
|
||||
else
|
||||
{
|
||||
int remainingMinutes = (int)Math.Floor(remainingSeconds / 60);
|
||||
message = $"验证码发送过于频繁,请{remainingMinutes}分钟后再试。";
|
||||
}
|
||||
|
||||
throw new CustomException(message);
|
||||
}
|
||||
|
||||
// 设置每天最大发送次数为5次
|
||||
const int maxDailyCount = 5;
|
||||
if (dailyCount >= maxDailyCount)
|
||||
{
|
||||
// 记录达到每日上限日志
|
||||
Logger.LogWarning($"手机号{phone}当天验证码发送次数已达上限({maxDailyCount}次)");
|
||||
throw new CustomException($"当天验证码发送次数已达上限,请明天再试");
|
||||
}
|
||||
|
||||
Random random = new Random();
|
||||
var verificationCode = random.Next(1000, 9999);
|
||||
var redisKey = $"VerificationCode:{phone}";
|
||||
var redisVerificationCode = RedisCache.StringGet<string>(redisKey);
|
||||
if (redisVerificationCode != null && !string.IsNullOrEmpty(redisVerificationCode))
|
||||
{
|
||||
throw new Exception("验证码已发送!");
|
||||
}
|
||||
|
||||
TencentSMSSendVerificationCode tencentSMSSendVerificationCode = new TencentSMSSendVerificationCode(smsConfig, phone);
|
||||
var result = await tencentSMSSendVerificationCode.SendVerificationCode(verificationCode.ToString(), 5);
|
||||
if (!result)
|
||||
{
|
||||
throw new Exception("验证码发送失败");
|
||||
}
|
||||
await RedisCache.StringSetAsync(redisKey, verificationCode.ToString(), TimeSpan.FromMinutes(5));
|
||||
// 获取客户端真实IP地址
|
||||
string ipAddress = GetRealIpAddress();
|
||||
|
||||
return "验证码已发送";
|
||||
try
|
||||
{
|
||||
TencentSMSSendVerificationCode tencentSMSSendVerificationCode = new TencentSMSSendVerificationCode(smsConfig, phone);
|
||||
var result = await tencentSMSSendVerificationCode.SendVerificationCode(verificationCode.ToString(), 5);
|
||||
if (!result)
|
||||
{
|
||||
// 记录发送失败日志
|
||||
Logger.LogError($"验证码发送失败,手机号:{phone},IP:{ipAddress}");
|
||||
throw new CustomException("验证码发送失败");
|
||||
}
|
||||
|
||||
// 发送成功,存入Redis,5分钟有效期
|
||||
await RedisCache.StringSetAsync(redisKey, verificationCode.ToString(), TimeSpan.FromMinutes(5));
|
||||
|
||||
// 更新重试次数和锁定时间
|
||||
retryCount++;
|
||||
var nextWaitSeconds = GetWaitSeconds(retryCount);
|
||||
|
||||
// 设置不能重发的锁
|
||||
await RedisCache.StringSetAsync(resendLockKey, "1", TimeSpan.FromSeconds(waitSeconds));
|
||||
|
||||
// 更新重试次数,5分钟后过期
|
||||
await RedisCache.StringSetAsync(retryCountKey, retryCount.ToString(), TimeSpan.FromMinutes(5));
|
||||
|
||||
// 更新当天发送次数计数并设置过期时间为当天剩余时间
|
||||
dailyCount++;
|
||||
var endOfDay = DateTime.Today.AddDays(1).AddSeconds(-1); // 当天23:59:59
|
||||
var expireTime = endOfDay - DateTime.Now;
|
||||
await RedisCache.StringSetAsync(dailyCountKey, dailyCount.ToString(), expireTime);
|
||||
|
||||
// 保存到数据库
|
||||
var verificationRecord = new UserVerificationCodes
|
||||
{
|
||||
UserId = userId,
|
||||
Account = phone,
|
||||
Code = verificationCode.ToString(),
|
||||
CodeType = codeType,
|
||||
Channel = "sms",
|
||||
IpAddress = ipAddress,
|
||||
Status = 0, // 未使用
|
||||
CreatedAt = DateTime.Now,
|
||||
UpdatedAt = DateTime.Now,
|
||||
ExpiredAt = DateTime.Now.AddMinutes(5)
|
||||
};
|
||||
|
||||
await Dao.Context.UserVerificationCodes.AddAsync(verificationRecord);
|
||||
await Dao.Context.SaveChangesAsync();
|
||||
|
||||
return nextWaitSeconds;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录异常日志
|
||||
Logger.LogError($"发送验证码异常:{ex.Message},手机号:{phone},IP:{ipAddress}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据重试次数获取等待时间
|
||||
/// </summary>
|
||||
/// <param name="retryCount">重试次数</param>
|
||||
/// <returns>等待秒数,-1表示不允许再次请求</returns>
|
||||
private int GetWaitSeconds(int retryCount)
|
||||
{
|
||||
return retryCount switch
|
||||
{
|
||||
0 => 30, // 第1次请求后等待30秒
|
||||
1 => 60, // 第2次请求后等待60秒
|
||||
2 => 60, // 第3次请求后等待60秒
|
||||
3 => 300, // 第4次请求后等待300秒(5分钟)
|
||||
4 => 300, // 第5次请求后等待300秒(5分钟)
|
||||
_ => -1 // 超过5次则不允许再次请求
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -296,4 +296,9 @@ public partial class Goods
|
|||
/// 每日限购次数
|
||||
/// </summary>
|
||||
public int DailyXiangou { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下架金额,当盒子利润值小于它时,下架(如100 盒子利润出现负数后,超过-100就下架)
|
||||
/// </summary>
|
||||
public int XiajiaJine { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,4 +39,14 @@ public partial class GoodsOffshelfLog
|
|||
/// 下架时间
|
||||
/// </summary>
|
||||
public int CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remarks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已读
|
||||
/// </summary>
|
||||
public int IsRead { get; set; }
|
||||
}
|
||||
|
|
|
|||
70
ChouBox.Model/Entities/UserVerificationCodes.cs
Normal file
70
ChouBox.Model/Entities/UserVerificationCodes.cs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ChouBox.Model.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 用户验证码表
|
||||
/// </summary>
|
||||
public partial class UserVerificationCodes
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键ID
|
||||
/// </summary>
|
||||
public ulong Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户ID,可为空表示未登录用户
|
||||
/// </summary>
|
||||
public ulong? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账号(手机号/邮箱)
|
||||
/// </summary>
|
||||
public string Account { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 验证码
|
||||
/// </summary>
|
||||
public string Code { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 验证码类型:1-注册,2-登录,3-找回密码,4-修改手机,5-修改邮箱,6-其他
|
||||
/// </summary>
|
||||
public sbyte CodeType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送渠道:sms-短信,email-邮件
|
||||
/// </summary>
|
||||
public string Channel { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 请求IP地址
|
||||
/// </summary>
|
||||
public string? IpAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态:0-未使用,1-已使用,2-已失效
|
||||
/// </summary>
|
||||
public sbyte Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 过期时间
|
||||
/// </summary>
|
||||
public DateTime ExpiredAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用时间
|
||||
/// </summary>
|
||||
public DateTime? UsedAt { get; set; }
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ using Pomelo.EntityFrameworkCore.MySql.Scaffolding.Internal;
|
|||
|
||||
namespace ChouBox.Model.Entities;
|
||||
|
||||
///
|
||||
public partial class YoudaContext : DbContext
|
||||
{
|
||||
public YoudaContext()
|
||||
|
|
@ -407,6 +406,11 @@ public partial class YoudaContext : DbContext
|
|||
/// </summary>
|
||||
public virtual DbSet<UserTaskList> UserTaskList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户验证码表
|
||||
/// </summary>
|
||||
public virtual DbSet<UserVerificationCodes> UserVerificationCodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会员vip
|
||||
/// </summary>
|
||||
|
|
@ -964,6 +968,8 @@ public partial class YoudaContext : DbContext
|
|||
|
||||
entity.HasIndex(e => e.Id, "id").IsUnique();
|
||||
|
||||
entity.HasIndex(e => new { e.UserId, e.Addtime, e.Status }, "idx_user_addtime_status");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasColumnType("int(10) unsigned")
|
||||
.HasColumnName("id");
|
||||
|
|
@ -1469,6 +1475,10 @@ public partial class YoudaContext : DbContext
|
|||
.HasComment("下架生效抽数")
|
||||
.HasColumnType("int(11)")
|
||||
.HasColumnName("xiajia_auto_coushu");
|
||||
entity.Property(e => e.XiajiaJine)
|
||||
.HasComment("下架金额,当盒子利润值小于它时,下架(如100 盒子利润出现负数后,超过-100就下架)")
|
||||
.HasColumnType("int(11)")
|
||||
.HasColumnName("xiajia_jine");
|
||||
entity.Property(e => e.XiajiaLirun)
|
||||
.HasComment("下架利润率")
|
||||
.HasColumnType("int(11)")
|
||||
|
|
@ -1807,6 +1817,10 @@ public partial class YoudaContext : DbContext
|
|||
.HasPrecision(10, 2)
|
||||
.HasComment("出货总价值")
|
||||
.HasColumnName("goods_total");
|
||||
entity.Property(e => e.IsRead)
|
||||
.HasComment("是否已读")
|
||||
.HasColumnType("int(11)")
|
||||
.HasColumnName("is_read");
|
||||
entity.Property(e => e.OrderTotal)
|
||||
.HasPrecision(10, 2)
|
||||
.HasComment("订单总价值")
|
||||
|
|
@ -1815,6 +1829,10 @@ public partial class YoudaContext : DbContext
|
|||
.HasPrecision(10, 2)
|
||||
.HasComment("当前利润率")
|
||||
.HasColumnName("profit_rate");
|
||||
entity.Property(e => e.Remarks)
|
||||
.HasMaxLength(1000)
|
||||
.HasComment("备注")
|
||||
.HasColumnName("remarks");
|
||||
entity.Property(e => e.XiajiaLirun)
|
||||
.HasPrecision(10, 2)
|
||||
.HasComment("配置的下架利润阈值")
|
||||
|
|
@ -2733,8 +2751,12 @@ public partial class YoudaContext : DbContext
|
|||
|
||||
entity.HasIndex(e => e.Id, "id").IsUnique();
|
||||
|
||||
entity.HasIndex(e => new { e.GoodsId, e.ShangId, e.ParentGoodsListId }, "idx_count_fast");
|
||||
|
||||
entity.HasIndex(e => new { e.GoodsId, e.UserId, e.Addtime }, "idx_gid_uid_time");
|
||||
|
||||
entity.HasIndex(e => new { e.ShangId, e.ParentGoodsListId, e.GoodsId, e.OrderType, e.Id }, "idx_opt_query");
|
||||
|
||||
entity.HasIndex(e => new { e.UserId, e.Addtime }, "idx_user_addtime");
|
||||
|
||||
entity.HasIndex(e => e.InsuranceIs, "insurance_is");
|
||||
|
|
@ -3922,7 +3944,7 @@ public partial class YoudaContext : DbContext
|
|||
.HasColumnType("int(11) unsigned")
|
||||
.HasColumnName("mb_number");
|
||||
entity.Property(e => e.Mobile)
|
||||
.HasMaxLength(11)
|
||||
.HasMaxLength(15)
|
||||
.HasComment("手机号")
|
||||
.HasColumnName("mobile");
|
||||
entity.Property(e => e.Money)
|
||||
|
|
@ -4739,6 +4761,71 @@ public partial class YoudaContext : DbContext
|
|||
.HasColumnName("z_number");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<UserVerificationCodes>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity.ToTable("user_verification_codes", tb => tb.HasComment("用户验证码表"));
|
||||
|
||||
entity.HasIndex(e => new { e.Account, e.CodeType }, "idx_account_code_type");
|
||||
|
||||
entity.HasIndex(e => e.Code, "idx_code");
|
||||
|
||||
entity.HasIndex(e => e.ExpiredAt, "idx_expired_at");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasComment("主键ID")
|
||||
.HasColumnType("bigint(20) unsigned")
|
||||
.HasColumnName("id");
|
||||
entity.Property(e => e.Account)
|
||||
.HasMaxLength(100)
|
||||
.HasComment("账号(手机号/邮箱)")
|
||||
.HasColumnName("account");
|
||||
entity.Property(e => e.Channel)
|
||||
.HasMaxLength(20)
|
||||
.HasComment("发送渠道:sms-短信,email-邮件")
|
||||
.HasColumnName("channel");
|
||||
entity.Property(e => e.Code)
|
||||
.HasMaxLength(20)
|
||||
.HasComment("验证码")
|
||||
.HasColumnName("code");
|
||||
entity.Property(e => e.CodeType)
|
||||
.HasComment("验证码类型:1-注册,2-登录,3-找回密码,4-修改手机,5-修改邮箱,6-其他")
|
||||
.HasColumnType("tinyint(4)")
|
||||
.HasColumnName("code_type");
|
||||
entity.Property(e => e.CreatedAt)
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP")
|
||||
.HasComment("创建时间")
|
||||
.HasColumnType("datetime")
|
||||
.HasColumnName("created_at");
|
||||
entity.Property(e => e.ExpiredAt)
|
||||
.HasComment("过期时间")
|
||||
.HasColumnType("datetime")
|
||||
.HasColumnName("expired_at");
|
||||
entity.Property(e => e.IpAddress)
|
||||
.HasMaxLength(50)
|
||||
.HasComment("请求IP地址")
|
||||
.HasColumnName("ip_address");
|
||||
entity.Property(e => e.Status)
|
||||
.HasComment("状态:0-未使用,1-已使用,2-已失效")
|
||||
.HasColumnType("tinyint(4)")
|
||||
.HasColumnName("status");
|
||||
entity.Property(e => e.UpdatedAt)
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP")
|
||||
.HasComment("更新时间")
|
||||
.HasColumnType("datetime")
|
||||
.HasColumnName("updated_at");
|
||||
entity.Property(e => e.UsedAt)
|
||||
.HasComment("使用时间")
|
||||
.HasColumnType("datetime")
|
||||
.HasColumnName("used_at");
|
||||
entity.Property(e => e.UserId)
|
||||
.HasComment("用户ID,可为空表示未登录用户")
|
||||
.HasColumnType("bigint(20) unsigned")
|
||||
.HasColumnName("user_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<UserVip>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ dotnet ef dbcontext scaffold "Server=192.168.1.56;Database=youda;User=youda;Pass
|
|||
|
||||
|
||||
dotnet ef dbcontext scaffold "Server=192.168.1.56;Database=youda;User=youda;Password=youda;" Pomelo.EntityFrameworkCore.MySql -o Entities/ --use-database-names --no-pluralize --force --context-dir Context --project ChouBox.Model
|
||||
dotnet ef dbcontext scaffold "Server=192.168.1.56;Database=youda;User=youda;Password=youda;" Pomelo.EntityFrameworkCore.MySql -o Entities/ --no-pluralize --force
|
||||
dotnet ef dbcontext scaffold "server=192.168.195.13;port=3306;database=youda;user=youda;password=youda;charset=utf8mb4" Pomelo.EntityFrameworkCore.MySql -o Entities/ --no-pluralize --force
|
||||
```
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
using HuanMeng.DotNetCore.AttributeExtend;
|
||||
using HuanMeng.DotNetCore.Base;
|
||||
using HuanMeng.DotNetCore.Extensions;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ namespace ChouBox.WebApi.Controllers;
|
|||
/// <param name="serviceProvider"></param>
|
||||
[Route("api/v2/[controller]")]
|
||||
[ApiController]
|
||||
public class AccountController(IServiceProvider serviceProvider) : ControllerBase
|
||||
public class AccountController(IServiceProvider serviceProvider, IHttpContextAccessor httpContextAccessor) : ControllerBase
|
||||
{
|
||||
|
||||
|
||||
|
|
@ -25,9 +26,10 @@ public class AccountController(IServiceProvider serviceProvider) : ControllerBas
|
|||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("sendSms")]
|
||||
public async Task<string> SendPhoneAsync([FromForm]string phone)
|
||||
[Message("验证码发送成功!")]
|
||||
public async Task<int> SendPhoneAsync([FromForm] string phone)
|
||||
{
|
||||
SMSBLL sms = new SMSBLL(serviceProvider);
|
||||
return await sms.SendPhoneAsync(phone);
|
||||
return await sms.SendPhoneAsync(phone); ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,15 +56,112 @@ namespace ChouBox.WebApi.Filters
|
|||
context.Result = new JsonResult(response);
|
||||
}
|
||||
// 处理其他类型的结果(如ActionResult<string>)
|
||||
else if (context.Result is ObjectResult objResult && objResult.Value is string stringValue)
|
||||
else if (context.Result is ObjectResult objResult)
|
||||
{
|
||||
var response = new BaseResponse<string>
|
||||
// 处理基础类型
|
||||
if (objResult.Value is string stringValue)
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = stringValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
var response = new BaseResponse<string>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = stringValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
else if (objResult.Value is int intValue)
|
||||
{
|
||||
var response = new BaseResponse<int>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = intValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
else if (objResult.Value is bool boolValue)
|
||||
{
|
||||
var response = new BaseResponse<bool>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = boolValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
else if (objResult.Value is long longValue)
|
||||
{
|
||||
var response = new BaseResponse<long>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = longValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
else if (objResult.Value is double doubleValue)
|
||||
{
|
||||
var response = new BaseResponse<double>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = doubleValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
else if (objResult.Value is decimal decimalValue)
|
||||
{
|
||||
var response = new BaseResponse<decimal>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = decimalValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
else if (objResult.Value is DateTime dateTimeValue)
|
||||
{
|
||||
var response = new BaseResponse<DateTime>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = dateTimeValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
else if (objResult.Value is Guid guidValue)
|
||||
{
|
||||
var response = new BaseResponse<Guid>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = guidValue
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
// 如果不是基础类型,则直接使用object类型的BaseResponse
|
||||
else if (objResult.Value != null)
|
||||
{
|
||||
// 处理其他非基础类型
|
||||
var response = new BaseResponse<object>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = objResult.Value
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
// 处理null值
|
||||
else
|
||||
{
|
||||
var response = new BaseResponse<object>
|
||||
{
|
||||
Status = 1,
|
||||
Msg = customMessage,
|
||||
Data = null
|
||||
};
|
||||
context.Result = new JsonResult(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ builder.Services.AddEndpointsApiExplorer();
|
|||
builder.Services.AddSwaggerGen();
|
||||
builder.Services.AddScoped<ChouBoxCodeBase>();
|
||||
#region 添加跨域
|
||||
var _myAllowSpecificOrigins = "_myAllowSpecificOrigins";
|
||||
builder.Services.AddCustomCors(_myAllowSpecificOrigins);
|
||||
//var _myAllowSpecificOrigins = "_myAllowSpecificOrigins";
|
||||
//builder.Services.AddCustomCors(_myAllowSpecificOrigins);
|
||||
#endregion
|
||||
var app = builder.Build();
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ app.UseHttpsRedirection();
|
|||
|
||||
app.UseAuthorization();
|
||||
//使用跨域
|
||||
app.UseCors(_myAllowSpecificOrigins);
|
||||
//app.UseCors(_myAllowSpecificOrigins);
|
||||
|
||||
//执行扩展中间件
|
||||
app.UseMiddlewareAll();
|
||||
|
|
|
|||
|
|
@ -8,5 +8,12 @@
|
|||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}, //服务器配置
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://*:81"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
60
Utile/HuanMeng.DotNetCore/Base/CustomException.cs
Normal file
60
Utile/HuanMeng.DotNetCore/Base/CustomException.cs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HuanMeng.DotNetCore.Base
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义异常类,用于特定业务场景
|
||||
/// 该异常被捕获时不会记录日志,适用于普通业务逻辑错误
|
||||
/// </summary>
|
||||
public class CustomException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// 错误参数名
|
||||
/// </summary>
|
||||
public string ParamName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建自定义异常
|
||||
/// </summary>
|
||||
/// <param name="message">错误消息</param>
|
||||
public CustomException(string message) : base(message)
|
||||
{
|
||||
ParamName = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建自定义异常
|
||||
/// </summary>
|
||||
/// <param name="message">错误消息</param>
|
||||
/// <param name="paramName">参数名</param>
|
||||
public CustomException(string message, string paramName) : base(message)
|
||||
{
|
||||
ParamName = paramName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建自定义异常
|
||||
/// </summary>
|
||||
/// <param name="message">错误消息</param>
|
||||
/// <param name="innerException">内部异常</param>
|
||||
public CustomException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
ParamName = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建自定义异常
|
||||
/// </summary>
|
||||
/// <param name="message">错误消息</param>
|
||||
/// <param name="paramName">参数名</param>
|
||||
/// <param name="innerException">内部异常</param>
|
||||
public CustomException(string message, string paramName, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
ParamName = paramName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,12 @@ public enum ResponseCode
|
|||
/// <summary>
|
||||
/// 成功
|
||||
/// </summary>
|
||||
Success = 0,
|
||||
Success = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 通用
|
||||
/// </summary>
|
||||
Common = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 正在处理中
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace HuanMeng.DotNetCore.MiddlewareExtend
|
|||
|
||||
|
||||
context.Response.StatusCode = StatusCodes.Status200OK;
|
||||
BaseResponse<object> baseResponse = new BaseResponse<object>(ResponseCode.ParamError, ex.ParamName ?? "参数错误", null)
|
||||
BaseResponse<object> baseResponse = new BaseResponse<object>(ResponseCode.Common, ex.ParamName ?? "参数错误", null)
|
||||
{
|
||||
|
||||
};
|
||||
|
|
@ -44,6 +44,15 @@ namespace HuanMeng.DotNetCore.MiddlewareExtend
|
|||
// 将异常信息写入 HTTP 响应
|
||||
await context.Response.WriteAsync(baseResponse.ToString());
|
||||
}
|
||||
catch (CustomException ex)
|
||||
{
|
||||
// 对自定义异常的特殊处理,不记录日志
|
||||
context.Response.StatusCode = StatusCodes.Status200OK;
|
||||
BaseResponse<object> baseResponse = new BaseResponse<object>(ResponseCode.Common, ex.ParamName ?? "", null);
|
||||
context.Response.ContentType = "application/json; charset=utf-8";
|
||||
// 将异常信息写入 HTTP 响应
|
||||
await context.Response.WriteAsync(baseResponse.ToString());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user