5 changed files with 267 additions and 0 deletions
@ -0,0 +1,42 @@
|
||||
using ATS.NonCustodial.Domain.Shared.AggRootEntities; |
||||
using ATS.NonCustodial.Domain.Shared.Constants; |
||||
using ATS.NonCustodial.Domain.Shared.Enums; |
||||
using ATS.NonCustodial.Shared.Common.Enums; |
||||
using ATS.NonCustodial.Shared.Common.Enums.IM; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using System.ComponentModel.DataAnnotations; |
||||
using System.ComponentModel.DataAnnotations.Schema; |
||||
using System.Numerics; |
||||
|
||||
namespace ATS.NonCustodial.Domain.Entities.Admins |
||||
{ |
||||
[Table("app_sms")] |
||||
public class AppSMS: EntityFull |
||||
{ |
||||
public AppSMS() |
||||
{ } |
||||
|
||||
public AppSMS(long id) |
||||
{ |
||||
Id = id; |
||||
} |
||||
|
||||
public string phone { get; set; } = string.Empty; |
||||
|
||||
public string content { get; set; } = string.Empty; |
||||
|
||||
public string? code { get; set; } |
||||
|
||||
public DateTime sendTime { get; set; } |
||||
|
||||
public DateTime expiresTime { get; set; } |
||||
|
||||
public bool isUsed { get; set; } = false; |
||||
|
||||
public DateTime? useTime { get; set; } |
||||
|
||||
public string ipAddress { get; set; } = string.Empty; |
||||
|
||||
public string type { get; set; } = "default"; |
||||
} |
||||
} |
||||
@ -0,0 +1,170 @@
|
||||
using ATS.NonCustodial.Application.Base; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Auth; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Auth.Input; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Auth.Output; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.User; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Input; |
||||
using ATS.NonCustodial.Domain.Entities.Admins; |
||||
using ATS.NonCustodial.Domain.Entities.Business; |
||||
using ATS.NonCustodial.Domain.Entities.Business.EarlyWarning; |
||||
using ATS.NonCustodial.Domain.Shared.Enums; |
||||
using ATS.NonCustodial.Domain.Shared.OrmRepositories.Basic.EfCore; |
||||
using ATS.NonCustodial.DynamicApi; |
||||
using ATS.NonCustodial.DynamicApi.Attributes; |
||||
using ATS.NonCustodial.Shared.Captcha.Dto; |
||||
using ATS.NonCustodial.Shared.Common.Attributes; |
||||
using ATS.NonCustodial.Shared.Common.Auth; |
||||
using ATS.NonCustodial.Shared.Common.Constants; |
||||
using ATS.NonCustodial.Shared.Common.Dtos; |
||||
using ATS.NonCustodial.Shared.Common.Enums; |
||||
using ATS.NonCustodial.Shared.Common.UnifiedResults; |
||||
using ATS.NonCustodial.Shared.Configurations.Options; |
||||
using ATS.NonCustodial.Shared.Extensions; |
||||
using ATS.NonCustodial.Shared.Helpers; |
||||
using ATS.NonCustodial.Shared.Helpers.Core.Hash; |
||||
using ATS.NonCustodial.Shared.Helpers.Http; |
||||
using ATS.NonCustodial.Shared.Tools.Captcha; |
||||
using Microsoft.AspNetCore.Authorization; |
||||
using Microsoft.AspNetCore.Cors; |
||||
using Microsoft.AspNetCore.Mvc; |
||||
using Microsoft.AspNetCore.Mvc.ModelBinding; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using Microsoft.Extensions.Logging; |
||||
using Newtonsoft.Json; |
||||
using NPOI.SS.Formula.Functions; |
||||
using NPOI.Util; |
||||
using StackExchange.Profiling; |
||||
using System.Diagnostics; |
||||
using System.Security.Claims; |
||||
using static System.Runtime.InteropServices.JavaScript.JSType; |
||||
|
||||
namespace ATS.NonCustodial.Application.Impl.Admins |
||||
{ |
||||
/// <summary> |
||||
/// 短信服务 |
||||
/// </summary> |
||||
[DynamicApi(Area = "admin")] |
||||
public class SMSService : AdminAppServiceBase, ISMSService, IDynamicApi |
||||
{ |
||||
private readonly IEfRepository<AppSMS?, long> _appSMSRepository; |
||||
|
||||
public SMSService( |
||||
IEfRepository<AppSMS?, long> appSMSRepository) |
||||
{ |
||||
_appSMSRepository = appSMSRepository; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 发送验证码 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <param name="ipAddress"></param> |
||||
/// <param name="type"></param> |
||||
/// <returns></returns> |
||||
[HttpGet] |
||||
[AllowAnonymous] |
||||
public async Task<IResultOutput> SendCheckCodeSMS(string phone, string ipAddress = "", string type = "CheckCode") |
||||
{ |
||||
// 检查是否可以发送(一分钟内只能发送一次) |
||||
if (!await CanSendCodeAsync(phone)) |
||||
{ |
||||
return ResultOutput.NotOk("请求过于频繁,请稍后再试"); |
||||
} |
||||
|
||||
// 生成随机验证码(6位数字) |
||||
var random = new Random(); |
||||
var code = random.Next(100000, 999999).ToString(); |
||||
|
||||
// 创建验证码记录 |
||||
var addSMS = new AppSMS |
||||
{ |
||||
phone = phone, |
||||
code = code, |
||||
sendTime = DateTime.UtcNow, |
||||
expiresTime = DateTime.UtcNow.AddMinutes(5), // 5分钟有效期 |
||||
ipAddress = ipAddress, |
||||
type = type |
||||
}; |
||||
|
||||
// 发送短信 |
||||
var sendResult = SendSMS(phone, code); |
||||
if (!sendResult) |
||||
{ |
||||
return ResultOutput.NotOk("短信发送失败,请稍后重试"); |
||||
} |
||||
|
||||
var sms = await _appSMSRepository.InsertAsync(addSMS); |
||||
|
||||
return ResultOutput.Ok(true); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 校验验证码 |
||||
/// </summary> |
||||
/// <param name="phoneNumber"></param> |
||||
/// <param name="code"></param> |
||||
/// <param name="type"></param> |
||||
/// <returns></returns> |
||||
public async Task<bool> CheckCodeAsync(string phoneNumber, string code, string type = "default") |
||||
{ |
||||
var now = DateTime.UtcNow; |
||||
|
||||
// 查找有效的验证码 |
||||
var validCode = await _appSMSRepository.AsQueryable() |
||||
.Where(v => v.phone == phoneNumber |
||||
&& v.code == code |
||||
&& v.type == type |
||||
&& !v.isUsed |
||||
&& v.expiresTime > now) |
||||
.OrderByDescending(v => v.sendTime) |
||||
.FirstOrDefaultAsync(); |
||||
|
||||
if (validCode == null) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
// 标记为已使用 |
||||
validCode.isUsed = true; |
||||
validCode.useTime = now; |
||||
await _appSMSRepository.UpdateAsync(validCode); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 发送前校验 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <returns></returns> |
||||
public async Task<bool> CanSendCodeAsync(string phone) |
||||
{ |
||||
var oneMinuteAgo = DateTime.UtcNow.AddMinutes(-1); |
||||
|
||||
// 检查一分钟内是否有发送记录 |
||||
var recentCode = await _appSMSRepository.AsQueryable() |
||||
.Where(v => v.phone == phone |
||||
&& v.sendTime > oneMinuteAgo) |
||||
.OrderByDescending(v => v.sendTime) |
||||
.FirstOrDefaultAsync(); |
||||
|
||||
return recentCode == null; |
||||
} |
||||
|
||||
#region Private |
||||
|
||||
/// <summary> |
||||
/// 发送短信 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <param name="msg"></param> |
||||
/// <returns></returns> |
||||
private bool SendSMS(string phone, string msg) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
#endregion |
||||
} |
||||
} |
||||
@ -0,0 +1,36 @@
|
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Auth.Input; |
||||
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Auth.Output; |
||||
using ATS.NonCustodial.Domain.Shared.Enums; |
||||
using ATS.NonCustodial.Shared.Captcha.Dto; |
||||
using ATS.NonCustodial.Shared.Common.Dtos; |
||||
using ATS.NonCustodial.Shared.Common.UnifiedResults; |
||||
|
||||
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Admins.SMS |
||||
{ |
||||
public interface ISMSService |
||||
{ |
||||
/// <summary> |
||||
/// 发送验证码 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <returns></returns> |
||||
Task<IResultOutput> SendCheckCodeSMS(string phone, string ipAddress = "", string type = "CheckCode"); |
||||
|
||||
/// <summary> |
||||
/// 校验验证码 |
||||
/// </summary> |
||||
/// <param name="phoneNumber"></param> |
||||
/// <param name="code"></param> |
||||
/// <param name="type"></param> |
||||
/// <returns></returns> |
||||
Task<bool> CheckCodeAsync(string phoneNumber, string code, string type = "default"); |
||||
|
||||
|
||||
/// <summary> |
||||
/// 发送前校验 |
||||
/// </summary> |
||||
/// <param name="phone"></param> |
||||
/// <returns></returns> |
||||
Task<bool> CanSendCodeAsync(string phone); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue