/// <summary> /// 验证手机号码 /// </summary> /// <param name="input"></param> /// <returns></returns> /// <remarks> /// 用户传递手机号码及认证类型 /// 1、如果认证类型为注册: /// 先查询是否存在此手机号的缓存验证码信息,如果存在,抛出不能重复发送验证码异常 /// 随机生成6位纯数字验证码,通过短信接口服务发送到用户手机,并缓存验证码,设定一个有效时长 /// /// 2、如果认证类型为登录: /// 先查询是否存在此手机号的缓存验证码信息,如果存在,抛出不能重复发送验证码异常 /// 通过手机号查询用户信息,如果用户不存在,抛出手机号未注册异常 /// 调用PhoneNumberTokenProvider接口生成6位手机验证码,用途为 phone_verify /// 发送手机验证码到用户手机,并缓存验证码,设定一个有效时长 /// /// 用户调用 IdentityServer4/connect/token 登录系统(需要引用LINGYUN.Abp.IdentityServer.SmsValidator模块) /// 参数1:grant_type=phone_verify /// 参数2:phone_number=手机号码 /// 参数3:phone_verify_code=手机验证码 /// 参数4:client_id=客户端标识 /// 参数5:client_secret=客户端密钥 /// </remarks> public virtual async Task VerifyPhoneNumberAsync(VerifyDto input) { // TODO: 借用TOTP算法生成6位动态验证码 var verifyCodeExpiration = await SettingProvider.GetAsync <int>(AccountSettingNames.PhoneVerifyCodeExpiration); var phoneVerifyCacheKey = NormalizeCacheKey(input.PhoneNumber); var verifyCacheItem = await Cache.GetAsync(phoneVerifyCacheKey); if (verifyCacheItem != null) { throw new UserFriendlyException(L["PhoneVerifyCodeNotRepeatSend", verifyCodeExpiration]); } verifyCacheItem = new AccountRegisterVerifyCacheItem { PhoneNumber = input.PhoneNumber, }; switch (input.VerifyType) { case PhoneNumberVerifyType.Register: var phoneVerifyCode = new Random().Next(100000, 999999); verifyCacheItem.VerifyCode = phoneVerifyCode.ToString(); var templateCode = await SettingProvider.GetOrDefaultAsync(AccountSettingNames.SmsRegisterTemplateCode, ServiceProvider); await SendPhoneVerifyMessageAsync(templateCode, input.PhoneNumber, phoneVerifyCode.ToString()); break; case PhoneNumberVerifyType.Signin: var phoneSigninCode = await SendSigninVerifyCodeAsync(input.PhoneNumber); verifyCacheItem.VerifyCode = phoneSigninCode; break; case PhoneNumberVerifyType.ResetPassword: var resetPasswordCode = new Random().Next(100000, 999999); verifyCacheItem.VerifyCode = resetPasswordCode.ToString(); var resetPasswordToken = await SendResetPasswordVerifyCodeAsync(input.PhoneNumber, verifyCacheItem.VerifyCode); verifyCacheItem.VerifyToken = resetPasswordToken; break; } var cacheOptions = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(verifyCodeExpiration) }; await Cache.SetAsync(phoneVerifyCacheKey, verifyCacheItem, cacheOptions); }
protected virtual async Task <string> SendResetPasswordVerifyCodeAsync(string phoneNumber, string phoneVerifyCode) { // 查找用户信息 var user = await GetUserByPhoneNumberAsync(phoneNumber); // 获取登录验证码模板号 var templateCode = await SettingProvider.GetOrDefaultAsync(AccountSettingNames.SmsResetPasswordTemplateCode, ServiceProvider); // 生成重置密码验证码 var phoneVerifyToken = await UserManager.GeneratePasswordResetTokenAsync(user); // 发送短信验证码 await SendPhoneVerifyMessageAsync(templateCode, user.PhoneNumber, phoneVerifyCode); return(phoneVerifyToken); }
/// <summary> /// 发送登录验证码 /// </summary> /// <param name="phoneNumber">手机号</param> /// <returns>返回登录验证码</returns> protected virtual async Task <string> SendSigninVerifyCodeAsync(string phoneNumber) { // 查找用户信息 var user = await GetUserByPhoneNumberAsync(phoneNumber); // 获取登录验证码模板号 var templateCode = await SettingProvider.GetOrDefaultAsync(AccountSettingNames.SmsSigninTemplateCode, ServiceProvider); // 生成手机验证码 var phoneVerifyCode = await PhoneNumberTokenProvider.GenerateAsync("phone_verify", UserManager, user); // 发送短信验证码 await SendPhoneVerifyMessageAsync(templateCode, user.PhoneNumber, phoneVerifyCode); return(phoneVerifyCode); }
public virtual async Task CreateFileAsync([FromForm] FileUploadDto input) { // 检查文件大小 var fileSizeLimited = await SettingProvider .GetAsync( AbpFileManagementSettingNames.FileLimitLength, AbpFileManagementSettingNames.DefaultFileLimitLength); if (fileSizeLimited * 1024 * 1024 < input.TotalSize) { throw new UserFriendlyException(L["UploadFileSizeBeyondLimit", fileSizeLimited]); } // 采用分块模式上传文件 // 保存分块到临时目录 var fileName = input.FileName; // 文件扩展名 var fileExtensionName = FileHelper.GetExtension(fileName); var fileAllowExtension = await SettingProvider .GetOrDefaultAsync(AbpFileManagementSettingNames.AllowFileExtensions, ServiceProvider); // 检查文件扩展名 if (!fileAllowExtension.Split(',') .Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) { throw new UserFriendlyException(L["NotAllowedFileExtensionName", fileExtensionName]); } // 以上传的文件名创建一个临时目录 var tempFilePath = Path.Combine( Path.GetTempPath(), "lingyun-abp-file-management", "upload", string.Concat(input.Path ?? "", input.FileName).ToMd5()); DirectoryHelper.CreateIfNotExists(tempFilePath); // 以上传的分片索引创建临时文件 var tempSavedFile = Path.Combine(tempFilePath, $"{input.ChunkNumber}.{fileExtensionName}"); try { if (HttpContext.RequestAborted.IsCancellationRequested) { // 如果取消请求,删除临时目录 Directory.Delete(tempFilePath, true); return; } if (input.File != null) { // 保存临时文件 using (var fs = new FileStream(tempSavedFile, FileMode.Create, FileAccess.Write)) { // 写入当前分片文件 await input.File.CopyToAsync(fs); } } if (input.ChunkNumber == input.TotalChunks) { // 合并文件 var mergeSavedFile = Path.Combine(tempFilePath, $"{fileName}"); // 获取并排序所有分片文件 var mergeFiles = Directory.GetFiles(tempFilePath).OrderBy(f => f.Length).ThenBy(f => f); // 创建临时合并文件 input.Data = new byte[0]; foreach (var mergeFile in mergeFiles) { // 读取当前文件字节 var mergeFileBytes = await FileHelper.ReadAllBytesAsync(mergeFile); // 写入到合并文件流 input.Data = input.Data.Concat(mergeFileBytes).ToArray(); Array.Clear(mergeFileBytes, 0, mergeFileBytes.Length); // 删除已参与合并的临时文件分片 FileHelper.DeleteIfExists(mergeFile); } await FileSystemAppService.CreateFileAsync(input); // 文件保存之后删除临时文件目录 Directory.Delete(tempFilePath, true); } } catch { // 发生异常删除临时文件目录 Directory.Delete(tempFilePath, true); throw; } }