You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
5.8 KiB
171 lines
5.8 KiB
|
3 months ago
|
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
|
||
|
|
}
|
||
|
|
}
|