提交代码

This commit is contained in:
zpc 2024-11-12 03:00:25 +08:00
parent e081d46f0d
commit a5c5fc72db
37 changed files with 1273 additions and 320 deletions

View File

@ -1,9 +1,12 @@
using Bogus.DataSets;
using CloudGaming.Api.Base;
using CloudGaming.Code.Account;
using CloudGaming.Code.AppExtend;
using CloudGaming.Code.DataAccess;
using CloudGaming.Code.MiddlewareExtend;
using CloudGaming.DtoModel.Account;
using CloudGaming.DtoModel.Account.Login;
using CloudGaming.GameModel.Db.Db_Ext;
using HuanMeng.DotNetCore.AttributeExtend;
@ -11,6 +14,7 @@ using HuanMeng.DotNetCore.Base;
using HuanMeng.DotNetCore.Utility;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CloudGaming.Api.Controllers;
@ -36,4 +40,29 @@ public class AccountController : CloudGamingControllerBase
AccountBLL account = new AccountBLL(ServiceProvider);
return await account.SendPhoneNumber(phoneNumber.PhoneNumber);
}
/// <summary>
/// 登录接口
/// 登录数据格式(设备号的目的是用于以后的多设备登录)
/// 短信登录:{"phoneNumber":"手机号","verificationCode":"验证码","deviceNumber":"设备号"}
/// token登录请求标头需要带上Authorized的token {"deviceNumber":"设备号"}
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<AccountLogInResponse> LoginAsync([FromBody] BaseLoginParams baseLogin)
{
AccountBLL account = new AccountBLL(ServiceProvider);
return await account.LoginAsync();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize]
public async Task<bool> GetUserInfo()
{
return true;
}
}

View File

@ -1,10 +1,20 @@
using CloudGaming.Code.Sms;
using Alipay.EasySDK.Kernel;
using CloudGaming.Code.Account.Contract;
using CloudGaming.Code.Sms;
using CloudGaming.DtoModel.Account;
using CloudGaming.DtoModel.Account.Login;
using HuanMeng.DotNetCore.JwtInfrastructure;
using HuanMeng.DotNetCore.Redis;
using HuanMeng.DotNetCore.Utility;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
@ -29,13 +39,13 @@ namespace CloudGaming.Code.Account
{
if (!PhoneNumberValidator.IsPhoneNumber(PhoneNumber))
{
throw new MessageException(ResonseCode.PhoneNumberException, "手机号格式错误");
throw MessageBox.Show(ResonseCode.PhoneNumberException, "手机号格式错误");
}
var day = int.Parse(DateTime.Now.ToString("yyyyMMdd"));
var smsCount = await Dao.DaoExt.Context.T_Sms_Log.Where(it => it.SendTimeDay == day && it.PhoneNumber == PhoneNumber).CountAsync();
if (smsCount >= 5)
{
throw new MessageException(ResonseCode.PhoneNumberMaxException, "当日发送以达到上限");
throw MessageBox.Show(ResonseCode.PhoneNumberMaxException, "当日发送以达到上限");
}
var phoneNumberCache = RedisCache.StringGetAsync($"App:sms:{PhoneNumber}");
var verificationCode = new Random().Next(1000, 9999).ToString();
@ -59,6 +69,7 @@ namespace CloudGaming.Code.Account
{
await RedisCache.StringSetAsync($"App:sms:{PhoneNumber}", verificationCode, TimeSpan.FromMinutes(5));
}
T_Sms_Log t_Sms_Log = new T_Sms_Log()
{
VerificationCode = verificationCode,
@ -70,7 +81,214 @@ namespace CloudGaming.Code.Account
};
Dao.DaoExt.Context.T_Sms_Log.Add(t_Sms_Log);
await Dao.DaoExt.Context.SaveChangesAsync();
if (!isSend)
{
throw MessageBox.ErrorShow("发送失败");
}
return isSend;
}
/// <summary>
/// 登录接口
/// </summary>
/// <returns></returns>
public async Task<AccountLogInResponse> LoginAsync()
{
this.HttpContextAccessor.HttpContext.Request.Body.Position = 0;
var json = await new StreamReader(this.HttpContextAccessor.HttpContext.Request.Body).ReadToEndAsync();
if (string.IsNullOrEmpty(json))
{
throw MessageBox.Show(ResonseCode.NullOrEmpty, "登录方式不合格");
}
var account = AccountExtend.GetUserAccount(json, this);
if (account == null)
{
throw MessageBox.Show(ResonseCode.NullOrEmpty, "未找到登录方式");
}
var userId = await account.LoginAsync();
bool isNew = false;
if (userId == 0)
{
isNew = true;
}
var ip = this.HttpContextAccessor.HttpContext.GetClientIpAddress();
//登录或者注册用户
var user = await RegisterOrUpdateUserAsync(userId, account, ip);
//注册用户详细信息
var userData = await EnsureUserDataExistsAsync(user.Id, account);
//创建jwt登录
var jwt = GenerateJwtToken(user);
var accountLogIn = new AccountLogInResponse
{
NickName = user.NickName,
Token = jwt.AccessToken,
UserId = user.Id,
};
//创建设备号
var dev = await ManageUserDevicesAsync(user, account, jwt.AccessToken);
var key = $"user:login:{user.Id}";
var accountUserLoginInfos = await RedisCache.StringGetAsync<List<AccountUserLoginInfo>>(key);
accountUserLoginInfos ??= new List<AccountUserLoginInfo>();
//创建redis缓存
await RedisCache.StringSetAsync(key, $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", TimeSpan.FromHours(1));
//accountUserLoginInfos.Add(new AccountUserLoginInfo());
T_User_Login_Log login_Log = new T_User_Login_Log()
{
Channel = this.AppRequestInfo.Channel,
CreateTime = DateTime.Now,
CreateTimeDay = 0,
CreateTimeHour = 0,
AppVersion = this.AppRequestInfo.Version,
Ip = ip,
IsNew = isNew,
LoginType = account.LastLoginType,
PlatformType = this.AppRequestInfo.Platform,
UserId = user.Id,
};
await Dao.DaoExt.Context.AddAsync(login_Log);
await Dao.DaoExt.Context.SaveChangesAsync();
return accountLogIn;
}
#region
/// <summary>
/// 注册新用户或更新现有用户信息
/// </summary>
/// <param name="user"></param>
/// <param name="account"></param>
/// <param name="ip"></param>
/// <returns></returns>
private async Task<T_User> RegisterOrUpdateUserAsync(int userId, IUserAccount account, string ip)
{
var user = userId > 0
? await Dao.DaoUser.Context.T_User.FirstOrDefaultAsync(it => it.Id == userId)
: null;
if (user == null)
{
user = new T_User
{
CreatedAt = DateTime.Now,
LastLoginAt = DateTime.Now,
UpdatedAt = DateTime.Now,
IsTest = false,
LastLoginType = account.LastLoginType,
RegisterType = account.LastLoginType,
State = 0,
UserIconUrl = AppConfig.UserConfig.UserIconUrl,
NickName = $"{AppConfig.UserConfig.NickName}{new Random().Next(1000, 9999)}",
Ip = ip
};
await Dao.DaoUser.Context.T_User.AddAsync(user);
}
user.LastLoginAt = DateTime.Now;
user.UpdatedAt = DateTime.Now;
user.Ip = ip;
await Dao.DaoUser.Context.SaveChangesAsync();
return user;
}
// 确保用户数据存在
private async Task<T_User_Data> EnsureUserDataExistsAsync(int userId, IUserAccount account)
{
var userData = await Dao.DaoUser.Context.T_User_Data.FirstOrDefaultAsync(it => it.UserId == userId);
if (userData == null)
{
userData = new T_User_Data
{
CreateAt = DateTime.Now,
UpdateAt = DateTime.Now,
PhoneNum = account.GetUserDataProperty(UserDataPropertyEnum.PhoneNum),
UserId = userId,
Email = account.GetUserDataProperty(UserDataPropertyEnum.Email)
};
await Dao.DaoUser.Context.T_User_Data.AddAsync(userData);
await Dao.DaoUser.Context.SaveChangesAsync();
}
return userData;
}
// 生成JWT令牌
private JwtAuthResult GenerateJwtToken(T_User user)
{
var claims = new[]
{
new Claim("NickName", user.NickName),
new Claim("UserId", user.Id.ToString()),
};
return JwtAuthManager.GenerateTokens(user.NickName, claims, DateTime.Now);
}
// 管理用户设备
private async Task<T_User_Token> ManageUserDevicesAsync(T_User user, IUserAccount account, string accessToken)
{
var currentTime = DateTime.Now;
var dev = string.IsNullOrEmpty(account.DeviceNumber)
? MD5Encryption.ComputeMD5Hash($"{user.Id}:{account.LastLoginType}")
: account.DeviceNumber;
var userLoginList = await Dao.DaoUser.Context.T_User_Token
.Where(it => it.UserId == user.Id)
.OrderBy(it => it.LastLoginAt)
.ToListAsync();
// 删除多余的设备记录
if (userLoginList.Count > AppConfig.UserConfig.MaxDeviceCount)
{
var excessDevices = userLoginList.Take(userLoginList.Count - AppConfig.UserConfig.MaxDeviceCount).ToList();
Dao.DaoUser.Context.T_User_Token.RemoveRange(excessDevices);
await Dao.DaoUser.Context.SaveChangesAsync();
}
var existingDevice = userLoginList.FirstOrDefault(it => it.DeviceNumber == dev);
if (existingDevice == null)
{
if (userLoginList.Count == AppConfig.UserConfig.MaxDeviceCount)
{
// 替换最早登录的设备
existingDevice = userLoginList.First();
UpdateDeviceToken(existingDevice, dev, accessToken, currentTime);
}
else
{
// 新增设备记录
existingDevice = new T_User_Token
{
CreateAt = currentTime,
ExpiresAt = currentTime.AddDays(5),
LastLoginAt = currentTime,
Token = accessToken,
UserId = user.Id,
DeviceNumber = dev,
TokenMd5 = MD5Encryption.ComputeMD5Hash(accessToken)
};
await Dao.DaoUser.Context.T_User_Token.AddAsync(existingDevice);
}
}
else
{
// 更新现有设备信息
UpdateDeviceToken(existingDevice, dev, accessToken, currentTime);
}
await Dao.DaoUser.Context.SaveChangesAsync();
return existingDevice;
}
// 更新设备令牌信息
private void UpdateDeviceToken(T_User_Token device, string deviceNumber, string accessToken, DateTime currentTime)
{
device.DeviceNumber = deviceNumber;
device.TokenMd5 = MD5Encryption.ComputeMD5Hash(accessToken);
device.LastLoginAt = currentTime;
device.ExpiresAt = currentTime.AddDays(5);
device.Token = accessToken;
}
#endregion
}
}

View File

@ -0,0 +1,42 @@
using CloudGaming.Code.Account.Contract;
using CloudGaming.Code.Account.Login;
using CloudGaming.DtoModel.Account.Login;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.Account
{
public static class AccountExtend
{
/// <summary>
/// 返回对应的登录方式
/// </summary>
/// <param name="jsonString"></param>
/// <returns></returns>
public static IUserAccount? GetUserAccount(string jsonString, CloudGamingBase cloudGamingBase)
{
JObject jsonObject = JObject.Parse(jsonString);
if (AllKeysExistIgnoreCase(jsonObject, "PhoneNumber", "VerificationCode"))
{
var loginParams = JsonConvert.DeserializeObject<PhoneLoginParams>(jsonString);
PhoneUserLogin phoneUserLogin = new PhoneUserLogin(loginParams, cloudGamingBase);
return phoneUserLogin;
}
return null;
}
static bool AllKeysExistIgnoreCase(JObject jsonObject, params string[] keysToCheck)
{
var propertie = jsonObject.Properties();
return keysToCheck.All(key => propertie.Any(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase)));
}
}
}

View File

@ -0,0 +1,49 @@
using CloudGaming.DtoModel.Account;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.Account.Contract
{
/// <summary>
/// 登录接口
/// </summary>
public interface IUserAccount
{
/// <summary>
/// 登录方式
/// </summary>
public int LastLoginType { get; set; }
/// <summary>
/// 设备号
/// </summary>
public string DeviceNumber { get; }
/// <summary>
/// 登录
/// </summary>
/// <returns></returns>
Task<int> LoginAsync();
/// <summary>
/// 创建账号
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task CreateLoginAsync(T_User user);
/// <summary>
/// 获取用户属性
/// </summary>
/// <param name="userDataPropertyEnum"></param>
/// <returns></returns>
string GetUserDataProperty(UserDataPropertyEnum userDataPropertyEnum);
}
}

View File

@ -0,0 +1,116 @@
using Bogus.DataSets;
using CloudGaming.Code.Account.Contract;
using CloudGaming.DtoModel.Account;
using CloudGaming.DtoModel.Account.Login;
using HuanMeng.DotNetCore.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.Account.Login
{
/// <summary>
/// 手机号登录
/// </summary>
/// <param name="loginParams"></param>
/// <param name="cloudGamingBase"></param>
public class PhoneUserLogin(PhoneLoginParams loginParams, CloudGamingBase cloudGamingBase) : IUserAccount
{
public async Task<int> LoginAsync()
{
if (string.IsNullOrEmpty(loginParams.PhoneNumber))
{
throw MessageBox.Show(ResonseCode.ParamError, "手机号不能为空");
}
if (string.IsNullOrEmpty(loginParams.VerificationCode))
{
throw MessageBox.Show(ResonseCode.ParamError, "验证码不能为空");
}
//判断是否是测试账号
if (!loginParams.PhoneNumber.Contains("999999999") && loginParams.VerificationCode == "1112")
{
if (!PhoneNumberValidator.IsPhoneNumber(loginParams.PhoneNumber))
{
throw MessageBox.Show(ResonseCode.PhoneNumberException, "手机号格式错误");
}
var verificationCodeRedis = await cloudGamingBase.RedisCache.StringGetAsync($"App:sms:{loginParams.PhoneNumber}");
if (verificationCodeRedis.IsNullOrEmpty)
{
throw MessageBox.Show(ResonseCode.ParamError, "验证码已过期,请重新发送!");
}
var verificationCode = (string)verificationCodeRedis;
if (verificationCode != loginParams.VerificationCode)
{
throw MessageBox.Show(ResonseCode.ParamError, "验证码错误!");
}
await cloudGamingBase.RedisCache.KeyDeleteAsync($"App:sms:{loginParams.PhoneNumber}");
}
var userAccount = await cloudGamingBase.Dao.DaoUser.Context.T_User_Phone_Account.AsNoTracking().Where(it => it.PhoneNum == loginParams.PhoneNumber && !it.IsLogout).FirstOrDefaultAsync();
return userAccount?.UserId ?? 0;
}
/// <summary>
/// 创建登录账号
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public async Task CreateLoginAsync(T_User user)
{
T_User_Phone_Account t_User_Phone_Account = new T_User_Phone_Account()
{
UserId = user.Id,
IsLogout = false,
NikeName = user.NickName,
PhoneNum = loginParams.PhoneNumber,
UpdatedAt = DateTime.Now,
CreatedAt = DateTime.Now,
};
await cloudGamingBase.Dao.DaoUser.Context.T_User_Phone_Account.AddAsync(t_User_Phone_Account);
}
/// <summary>
///
/// </summary>
public int LastLoginType { get; set; } = 1;
/// <summary>
/// 返回登录信息
/// </summary>
/// <param name="userDataPropertyEnum"></param>
/// <returns></returns>
public string GetUserDataProperty(UserDataPropertyEnum userDataPropertyEnum)
{
if (userDataPropertyEnum == UserDataPropertyEnum.PhoneNum)
{
return loginParams.PhoneNumber;
}
return "";
}
/// <summary>
/// 设备号
/// </summary>
public string DeviceNumber
{
get
{
if (loginParams.DeviceNumber.Length > 100)
{
loginParams.DeviceNumber = loginParams.DeviceNumber.Substring(0, 100);
}
return loginParams.DeviceNumber;
}
}
}
}

View File

@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.AppExtend
{
/// <summary>
/// 阿里云配置
/// </summary>
public class AliyunConfig
{
/// <summary>
///
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
/// 配置环境变量
/// </summary>
public string AccessKeySecret { get; set; }
#region OSS配置
/// <summary>
/// 替换为Bucket所在地域对应的Endpoint。以华东1杭州为例Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
/// </summary>
public string EndPoint { get; set; }
/// <summary>
/// Bucket名称。
/// </summary>
public string BucketName { get; set; }
/// <summary>
/// 上传路径
/// </summary>
public string UploadPath { get; set; }
/// <summary>
/// 域名
/// </summary>
public string? DomainName { get; set; }
/// <summary>
/// 前缀
/// </summary>
public string ImagePrefix
{
get
{
return this.DomainName; //+ this.UploadPath
}
}
#endregion
/// <summary>
/// 短信签名名称
/// </summary>
public string SmsSignName { get; set; }
/// <summary>
/// string 短信模板配置
/// </summary>
public string SmsTemplateCode { get; set; }
}
}

View File

@ -1,117 +1,122 @@
using CloudGaming.Code.AppExtend.Config;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.AppExtend
namespace CloudGaming.Code.AppExtend;
/// <summary>
/// 项目配置
/// </summary>
public class AppConfig
{
public AppConfig() { }
/// <summary>
/// 项目配置
/// 用户数据库连接字符串
/// </summary>
public class AppConfig
public string UserConnectionString { get; set; }
/// <summary>
/// 游戏
/// </summary>
public string GameConnectionString { get; set; }
/// <summary>
/// 扩展
/// </summary>
public string ExtConnectionString { get; set; }
/// <summary>
/// 手机app配置
/// </summary>
public string PhoneConnectionString { get; set; }
/// <summary>
/// redis连接字符串
/// </summary>
public string RedisConnectionString { get; set; }
/// <summary>
/// 域名
/// </summary>
public string DomainName { get; set; }
/// <summary>
/// 标识
/// </summary>
public string Identifier { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 默认语言
/// </summary>
public string DefaultLanguage { get; set; }
/// <summary>
/// 租户
/// </summary>
public Guid TenantId { get; set; }
/// <summary>
/// 项目支付数据
/// </summary>
//public PaymentModel? Payment { get; set; }
/// <summary>
/// oss阿里云配置
/// </summary>
public AliyunConfig AliyunConfig { get; set; }
/// <summary>
/// 用户默认配置
/// </summary>
public UserConfig UserConfig { get; set; }
/// <summary>
/// 获取数据库连接字符串
/// </summary>
/// <param name="key">usergameextphone</param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public string GetConnectionString(AppDataBaseType appDataBaseType)
{
public AppConfig() { }
/// <summary>
/// 用户数据库连接字符串
/// </summary>
public string UserConnectionString { get; set; }
/// <summary>
/// 游戏
/// </summary>
public string GameConnectionString { get; set; }
/// <summary>
/// 扩展
/// </summary>
public string ExtConnectionString { get; set; }
/// <summary>
/// 手机app配置
/// </summary>
public string PhoneConnectionString { get; set; }
/// <summary>
/// redis连接字符串
/// </summary>
public string RedisConnectionString { get; set; }
/// <summary>
/// 域名
/// </summary>
public string DomainName { get; set; }
/// <summary>
/// 标识
/// </summary>
public string Identifier { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 默认语言
/// </summary>
public string DefaultLanguage { get; set; }
/// <summary>
/// 租户
/// </summary>
public Guid TenantId { get; set; }
/// <summary>
/// 项目支付数据
/// </summary>
//public PaymentModel? Payment { get; set; }
/// <summary>
/// oss阿里云配置
/// </summary>
public AliyunConfig AliyunConfig { get; set; }
/// <summary>
/// 获取数据库连接字符串
/// </summary>
/// <param name="key">usergameextphone</param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public string GetConnectionString(AppDataBaseType appDataBaseType)
switch (appDataBaseType)
{
switch (appDataBaseType)
{
case AppDataBaseType.User:
return UserConnectionString;
case AppDataBaseType.Game:
return GameConnectionString;
case AppDataBaseType.Ext:
return ExtConnectionString;
case AppDataBaseType.App:
return PhoneConnectionString;
default:
throw new NotImplementedException("数据库连接字符串不存在");
}
case AppDataBaseType.User:
return UserConnectionString;
case AppDataBaseType.Game:
return GameConnectionString;
case AppDataBaseType.Ext:
return ExtConnectionString;
case AppDataBaseType.App:
return PhoneConnectionString;
default:
throw new NotImplementedException("数据库连接字符串不存在");
}
}
/// <summary>
/// 数据库选项
/// </summary>
public enum AppDataBaseType
{
/// <summary>
/// 用户数据库
/// </summary>
User,
/// <summary>
/// 游戏数据库
/// </summary>
Game,
/// <summary>
/// 扩展数据库
/// </summary>
Ext,
/// <summary>
/// app数据库
/// </summary>
App
}
}
/// <summary>
/// 数据库选项
/// </summary>
public enum AppDataBaseType
{
/// <summary>
/// 用户数据库
/// </summary>
User,
/// <summary>
/// 游戏数据库
/// </summary>
Game,
/// <summary>
/// 扩展数据库
/// </summary>
Ext,
/// <summary>
/// app数据库
/// </summary>
App
}

View File

@ -176,6 +176,11 @@ namespace CloudGaming.Code.AppExtend
newAppConfig.PhoneConnectionString = appConfig.PhoneConnectionString;
newAppConfig.AliyunConfig = appConfig.AliyunConfig;
newAppConfig.DefaultLanguage = appConfig.DefaultLanguage;
if (appConfig.UserConfig == null)
{
appConfig.UserConfig = new UserConfig();
}
newAppConfig.UserConfig = appConfig.UserConfig;
return newAppConfig;
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.AppExtend.Config;
/// <summary>
/// 阿里云配置
/// </summary>
public class AliyunConfig
{
/// <summary>
///
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
/// 配置环境变量
/// </summary>
public string AccessKeySecret { get; set; }
#region OSS配置
/// <summary>
/// 替换为Bucket所在地域对应的Endpoint。以华东1杭州为例Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
/// </summary>
public string EndPoint { get; set; }
/// <summary>
/// Bucket名称。
/// </summary>
public string BucketName { get; set; }
/// <summary>
/// 上传路径
/// </summary>
public string UploadPath { get; set; }
/// <summary>
/// 域名
/// </summary>
public string? DomainName { get; set; }
/// <summary>
/// 前缀
/// </summary>
public string ImagePrefix
{
get
{
return this.DomainName; //+ this.UploadPath
}
}
#endregion
/// <summary>
/// 短信签名名称
/// </summary>
public string SmsSignName { get; set; }
/// <summary>
/// string 短信模板配置
/// </summary>
public string SmsTemplateCode { get; set; }
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.AppExtend.Config;
/// <summary>
/// 用户默认配置
/// </summary>
public class UserConfig
{
/// <summary>
/// 用户默认头像
/// </summary>
public string UserIconUrl { get; set; }
/// <summary>
/// 用户默认昵称
/// </summary>
public string NickName { get; set; }
/// <summary>
/// 用户最大登录设备
/// </summary>
public int MaxDeviceCount { get; set; }
}

View File

@ -8,6 +8,7 @@ using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text.Json;
namespace CloudGaming.Code.AppExtend
{
@ -65,6 +66,57 @@ namespace CloudGaming.Code.AppExtend
//指定允许令牌的时钟偏移。允许令牌的过期时间与实际时间之间存在的时间差。在这里设置为 5 分钟,表示允许令牌的时钟偏移为 5 分钟。
ClockSkew = TimeSpan.FromMinutes(5)
};
options.Events = new JwtBearerEvents
{
OnTokenValidated = async context =>
{
var userId = context.Principal.FindFirst("userId")?.Value;
if (userId == null || true)
{
context.Fail("Token missing userId claim.");
return;
}
//// 你可以调用数据库或其他服务来验证用户状态
//var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
//var user = await userService.GetUserByIdAsync(userId);
//if (user == null || !user.IsActive)
//{
// context.Fail("User is inactive or not found.");
//}
},
// 处理认证失败的事件
OnAuthenticationFailed = context =>
{
// 在这里可以根据需要设置自定义的HTTP状态码
context.Response.StatusCode = StatusCodes.Status403Forbidden; // 设置为 403 Forbidden
context.Response.ContentType = "application/json";
// 返回自定义的错误消息
var result = JsonSerializer.Serialize(new { error = context.Exception?.Message });
return context.Response.WriteAsync(result);
},
// 在认证失败并被 Challenge 时触发该事件
OnChallenge = context =>
{
// 如果已经有错误消息,则根据错误原因返回自定义状态码
if (context.AuthenticateFailure != null)
{
context.HandleResponse(); // 确保不再执行默认的挑战响应
context.Response.Clear(); // 清空现有响应内容
context.Response.StatusCode = StatusCodes.Status200OK; // 设置状态码为403 Forbidden
context.Response.ContentType = "application/json";
// 构建自定义的 JSON 响应
var result = JsonSerializer.Serialize(new { error = context.AuthenticateFailure.Message });
return context.Response.WriteAsync(result); // 写入响应
}
// 默认情况下返回 401 Unauthorized
return Task.CompletedTask;
}
};
});
//注册一个JwtAuthManager的单例服务
builder.Services.AddSingleton<IJwtAuthManager, JwtManager>();

View File

@ -29,6 +29,7 @@ namespace CloudGaming.Code.Config
IsAuthRealName = true
};
appConfigDto.IsChecking = IsChecking;
appConfigDto.SignKey = AppConfig.TenantId.ToString("N");
return appConfigDto;
}

View File

@ -14,7 +14,7 @@ namespace CloudGaming.Code.Filter
{
var sw = Stopwatch.StartNew();
// 检查异常是否是特定的异常类型
if (context.Exception is MessageException message)
if (context.Exception is MessageBox message)
{
var obj = new BaseResponse<object>(message.Code, message.Message, message.Data);
//// 处理特定异常:记录日志、设置响应结果等

View File

@ -19,5 +19,5 @@ global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting;
global using CloudGaming.Code.AppExtend.Config;
global using System.Diagnostics;

View File

@ -1,45 +1,46 @@
using HuanMeng.DotNetCore.MiddlewareExtend;
namespace CloudGaming.Code.MiddlewareExtend;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.MiddlewareExtend
/// <summary>
///
/// </summary>
public static class MiddlewareExtends
{
/// <summary>
///
/// 加载全部中间件
/// </summary>
public static class MiddlewareExtends
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseCloudGamingMiddlewareAll(this IApplicationBuilder builder)
{
/// <summary>
/// 加载全部中间件
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseCloudGamingMiddlewareAll(this IApplicationBuilder builder)
{
return builder
.UseCacheMiddleware()
.UseRedisCacheMiddleware()
;
}
/// <summary>
/// 缓存中间件
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseCacheMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MemoryCacheMiddleware>();
}
public static IApplicationBuilder UseRedisCacheMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RedisCacheMiddleware>();
}
return builder
.UseSignMiddleware()
.UseCacheMiddleware()
.UseRedisCacheMiddleware()
;
}
/// <summary>
/// 缓存中间件
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseCacheMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MemoryCacheMiddleware>();
}
public static IApplicationBuilder UseRedisCacheMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RedisCacheMiddleware>();
}
/// <summary>
/// 加密验证
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseSignMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SignMiddleware>();
}
}

View File

@ -0,0 +1,98 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.MiddlewareExtend;
/// <summary>
/// 参数请求加密验证
/// </summary>
public class SignMiddleware
{
private readonly RequestDelegate _next;
public SignMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context, AppConfig appConfig)
{ // 读取请求体
context.Request.EnableBuffering();
if (context.Request.Method != "POST" || context.Request.Host.Host == "localhost")
{
// 调用下一个中间件
await _next(context);
return;
}
// 启用请求流的多次读取功能
var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();
context.Request.Body.Position = 0; // 重置请求体的位置
if (string.IsNullOrEmpty(requestBody))
{
await _next(context);
return;
}
// 解析请求体为 JSON 对象
var requestJson = JObject.Parse(requestBody);
// 获取请求中的 sign 值
var requestSign = requestJson["sign"]?.ToString();
if (string.IsNullOrEmpty(requestSign))
{
var response = GetSignError(context);
context.Response.ContentType = "application/json; charset=utf-8";
await context.Response.WriteAsync(response);
return;
}
// 获取所有的键值对,并排序
var sortedKeys = requestJson.Properties()
.Where(p => p.Name != "sign")
.OrderBy(p => p.Name)
.Select(p => p.Value.ToString())
.ToList();
// 拼接所有的值,并加上固定字符串
var concatenatedValues = string.Join("", sortedKeys) + appConfig.TenantId.ToString("N");
// 计算 MD5 哈希值
var md5Hash = MD5Encryption.ComputeMD5Hash(concatenatedValues);
// 验证 MD5 哈希值与请求中的 sign 是否匹配
if (md5Hash != requestSign)
{
var response = GetSignError(context);
context.Response.ContentType = "application/json; charset=utf-8";
context.Response.Headers["X-Request-Sign-Value"] = concatenatedValues;
context.Response.Headers["X-Request-Sign"] = md5Hash;
// 将异常信息写入 HTTP 响应
await context.Response.WriteAsync(response);
//await context.Response.WriteAsync("");
return;
}
// 调用下一个中间件
await _next(context);
}
private static string GetSignError(HttpContext context)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
// 返回 500 错误
context.Response.StatusCode = 200;
BaseResponse<object> baseResponse = new BaseResponse<object>(ResonseCode.SignError, "sign加密验证失败", null)
{ };
var json = JsonConvert.SerializeObject(baseResponse, settings);
return json;
}
}

View File

@ -36,7 +36,7 @@ namespace CloudGaming.Code.Sms
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
AccessKeyId = "LTAI5tEMoHbcDC5d9CQWovJk",//aliyunOssConfig.AccessKeyId, //Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID"),
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
AccessKeySecret = "gnYOJr0l9hTnl82vI4BxwVgtE1RdL"// aliyunOssConfig.AccessKeySecret,
AccessKeySecret = "DgnYOJr0l9hTnl82vI4BxwVgtE1RdL"// aliyunOssConfig.AccessKeySecret,
};
// Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
config.Endpoint = "dysmsapi.aliyuncs.com";
@ -58,12 +58,15 @@ namespace CloudGaming.Code.Sms
SignName = aliyunOssConfig.SmsSignName,// "氢荷健康",
TemplateCode = aliyunOssConfig.SmsTemplateCode,// "SMS_154950909",
PhoneNumbers = phoneNumber,
TemplateParam = "{\"code\":\"" + code + "\"}",
TemplateParam = "{\"code\":\"" + code + "\"}"// "{\"code\":\"" + code + "\"}",
};
AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
try
{
// 复制代码运行请自行打印 API 的返回值
var response = await client.SendSmsWithOptionsAsync(sendSmsRequest, new AlibabaCloud.TeaUtil.Models.RuntimeOptions());
// 复制代码运行请自行打印 API 的返回值
//client.SendSmsWithOptions(sendSmsRequest, runtime);
var response = await client.SendSmsWithOptionsAsync(sendSmsRequest, runtime);
}
catch (TeaException error)
{
@ -72,7 +75,7 @@ namespace CloudGaming.Code.Sms
Console.WriteLine(error.Message);
// 诊断地址
Console.WriteLine(error.Data["Recommend"]);
AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
var x = AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
throw error;
}
catch (Exception _error)
@ -86,7 +89,7 @@ namespace CloudGaming.Code.Sms
Console.WriteLine(error.Message);
// 诊断地址
Console.WriteLine(error.Data["Recommend"]);
AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
var x = AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
throw error;
}

View File

@ -17,6 +17,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Model\CloudGaming.DtoModel\CloudGaming.DtoModel.csproj" />
<ProjectReference Include="..\..\Model\CloudGaming.Model\CloudGaming.Model.csproj" />
</ItemGroup>

View File

@ -1,8 +1,11 @@
// See https://aka.ms/new-console-template for more information
using CloudGaming.Model.DbSqlServer.Db_Phone;
using CloudGaming.Model.DbSqlServer.Db_User;
using CloudGaming.DtoModel.Account.Login;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
//var jsopn = JsonConvert.SerializeObject(new PhoneLoginParams());
//Server=192.168.1.17;Database=CloudGamingUser;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;
var optionsBuilder = new DbContextOptionsBuilder<CloudGamingPhoneContext>();
var option = optionsBuilder.UseSqlServer("Server=192.168.1.17;Database=CloudGamingPhone;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;").Options;

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.DtoModel.Account
{
/// <summary>
/// 登录返回的数据
/// </summary>
public class AccountLogInResponse
{
/// <summary>
/// token
/// </summary>
public string Token { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string NickName { get; set; }
/// <summary>
/// 用户id
/// </summary>
public int UserId { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.DtoModel.Account.Login
{
/// <summary>
///
/// </summary>
public class AccountUserLoginInfo
{
/// <summary>
/// 登录使用的tokens
/// </summary>
public string Token { get; set; }
/// <summary>
/// 过期时间
/// </summary>
public DateTime ExpirationDate { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.DtoModel.Account.Login
{
/// <summary>
///
/// </summary>
public class BaseLoginParams
{
/// <summary>
/// 设备号
/// </summary>
public string? DeviceNumber { get; set; } = "";
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.DtoModel.Account.Login;
/// <summary>
/// 验证码登录
/// </summary>
public class PhoneLoginParams : BaseLoginParams
{
/// <summary>
/// 手机号码
/// </summary>
public string PhoneNumber { get; set; }
/// <summary>
/// 验证码
/// </summary>
public string VerificationCode { get; set; }
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.DtoModel.Account
{
/// <summary>
/// 用户数据属性
/// </summary>
public enum UserDataPropertyEnum
{
/// <summary>
/// 手机号
/// </summary>
PhoneNum = 1,
/// <summary>
/// 邮箱
/// </summary>
Email = 2
}
}

View File

@ -31,7 +31,10 @@ public class AppConfigDto
//[Images]
//public int OpenImage { get; set; }
/// <summary>
/// 加密key
/// </summary>
public string SignKey { get; set; }
}

View File

@ -59,6 +59,11 @@ public partial class CloudGamingCBTContext : DbContext
/// </summary>
public virtual DbSet<T_Sms_Log> T_Sms_Log { get; set; }
/// <summary>
/// 用户登录日志表
/// </summary>
public virtual DbSet<T_User_Login_Log> T_User_Login_Log { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer("Server=192.168.1.17;Database=CloudGamingCBT;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;");
@ -150,14 +155,14 @@ public partial class CloudGamingCBTContext : DbContext
entity.ToTable(tb => tb.HasComment("发送短信日志表"));
entity.HasIndex(e => e.SendTimeDay, "T_Sms_Log_SendTimeDay_index_desc").IsDescending();
entity.HasIndex(e => new { e.SendTimeDay, e.PhoneNumber }, "T_Sms_Log_SendTimeDay_index_desc").IsDescending(true, false);
entity.Property(e => e.Id).HasComment("主键");
entity.Property(e => e.ErrorMessage)
.HasMaxLength(255)
.HasComment("错误信息(如果发送失败)");
entity.Property(e => e.PhoneNumber)
.HasMaxLength(1)
.HasMaxLength(20)
.HasComment("手机号码");
entity.Property(e => e.SendStatus).HasComment("发送状态0: 失败, 1: 成功)\r\n");
entity.Property(e => e.SendTime)
@ -165,11 +170,41 @@ public partial class CloudGamingCBTContext : DbContext
.HasColumnType("datetime");
entity.Property(e => e.SendTimeDay).HasComment("发送时间,天");
entity.Property(e => e.VerificationCode)
.HasMaxLength(1)
.HasMaxLength(20)
.HasComment("发送的验证码");
});
modelBuilder.Entity<T_User_Login_Log>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_User_L__3214EC07C2A990A7");
entity.ToTable(tb => tb.HasComment("用户登录日志表"));
entity.Property(e => e.Id).HasComment("主键");
entity.Property(e => e.AppVersion)
.HasMaxLength(10)
.HasComment("app版本");
entity.Property(e => e.Channel)
.HasMaxLength(20)
.HasComment("渠道");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.CreateTimeDay).HasComment("创建时间天");
entity.Property(e => e.CreateTimeHour).HasComment("创建时间小时");
entity.Property(e => e.Ip)
.HasMaxLength(50)
.HasComment("登录IP");
entity.Property(e => e.IsNew).HasComment("是否新增用户");
entity.Property(e => e.LoginType).HasComment("登录方式");
entity.Property(e => e.PlatformType)
.HasMaxLength(10)
.HasComment("登录平台");
entity.Property(e => e.UserId).HasComment("用户Id");
});
OnModelCreatingPartial(modelBuilder);
}

View File

@ -0,0 +1,66 @@
using System;
namespace CloudGaming.GameModel.Db.Db_Ext;
/// <summary>
/// 用户登录日志表
/// </summary>
public partial class T_User_Login_Log
{
public T_User_Login_Log() { }
/// <summary>
/// 主键
/// </summary>
public virtual int Id { get; set; }
/// <summary>
/// 用户Id
/// </summary>
public virtual int UserId { get; set; }
/// <summary>
/// 登录IP
/// </summary>
public virtual string Ip { get; set; } = null!;
/// <summary>
/// 是否新增用户
/// </summary>
public virtual bool IsNew { get; set; }
/// <summary>
/// 登录方式
/// </summary>
public virtual int LoginType { get; set; }
/// <summary>
/// 登录平台
/// </summary>
public virtual string PlatformType { get; set; } = null!;
/// <summary>
/// app版本
/// </summary>
public virtual string AppVersion { get; set; } = null!;
/// <summary>
/// 创建时间天
/// </summary>
public virtual int CreateTimeDay { get; set; }
/// <summary>
/// 创建时间小时
/// </summary>
public virtual int CreateTimeHour { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public virtual DateTime CreateTime { get; set; }
/// <summary>
/// 渠道
/// </summary>
public virtual string Channel { get; set; } = null!;
}

View File

@ -413,9 +413,6 @@ public partial class CloudGamingUserContext : MultiTenantDbContext//DbContext
.HasComment("修改时间")
.HasColumnType("datetime");
entity.Property(e => e.IsLogout).HasComment("是否注销");
entity.Property(e => e.LastLoginAt)
.HasComment("最后一次登录时间")
.HasColumnType("datetime");
entity.Property(e => e.NikeName)
.HasMaxLength(100)
.HasComment("用户昵称")
@ -430,11 +427,6 @@ public partial class CloudGamingUserContext : MultiTenantDbContext//DbContext
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.UserId).HasComment("用户Id");
entity.Property(e => e.VerificationCode)
.HasMaxLength(10)
.IsUnicode(false)
.HasComment("验证码")
.UseCollation("Chinese_PRC_CI_AS");
//添加全局筛选器
if (this.TenantInfo != null)
{
@ -451,11 +443,20 @@ public partial class CloudGamingUserContext : MultiTenantDbContext//DbContext
entity.Property(e => e.CreateAt)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.DeviceNumber)
.HasMaxLength(100)
.HasComment("设备号");
entity.Property(e => e.ExpiresAt)
.HasComment("过期时间")
.HasColumnType("datetime");
entity.Property(e => e.LastLoginAt)
.HasComment("最后一次登录时间")
.HasColumnType("datetime");
entity.Property(e => e.TenantId).HasComment("租户");
entity.Property(e => e.Token).HasComment("登录token");
entity.Property(e => e.TokenMd5)
.HasMaxLength(64)
.HasComment("tokenMd5值");
entity.Property(e => e.UpdateAt)
.HasComment("修改时间")
.HasColumnType("datetime");

View File

@ -29,16 +29,6 @@ public partial class T_User_Phone_Account: MultiTenantEntity
/// </summary>
public virtual string PhoneNum { get; set; } = null!;
/// <summary>
/// 验证码
/// </summary>
public virtual string VerificationCode { get; set; } = null!;
/// <summary>
/// 最后一次登录时间
/// </summary>
public virtual DateTime LastLoginAt { get; set; }
/// <summary>
/// 修改时间
/// </summary>

View File

@ -40,4 +40,19 @@ public partial class T_User_Token: MultiTenantEntity
/// 修改时间
/// </summary>
public virtual DateTime? UpdateAt { get; set; }
/// <summary>
/// 设备号
/// </summary>
public virtual string? DeviceNumber { get; set; }
/// <summary>
/// tokenMd5值
/// </summary>
public virtual string? TokenMd5 { get; set; }
/// <summary>
/// 最后一次登录时间
/// </summary>
public virtual DateTime LastLoginAt { get; set; }
}

View File

@ -0,0 +1,115 @@
using Microsoft.AspNetCore.SignalR.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.DotNetCore.Base
{
/// <summary>
///
/// </summary>
public class MessageBox : Exception
{
/// <summary>
///
/// </summary>
/// <param name="code"></param>
public MessageBox(ResonseCode code)
{
Code = (int)code;
Message = "";
}
/// <summary>
///
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public MessageBox(ResonseCode code, string message, object? data = null)
{
Code = (int)code;
Message = message;
Data = data;
}
/// <summary>
///
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public MessageBox(int code, string message, object? data = null)
{
Code = code;
Message = message;
Data = data;
}
/// <summary>
///
/// </summary>
/// <param name="message"></param>
/// <param name="data"></param>
public MessageBox(string message, object? data = null)
{
Code = 0;
Message = message;
Data = data;
}
/// <summary>
/// 功能执行返回代码
/// </summary>
public int Code { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 数据
/// </summary>
public object? Data { get; set; }
/// <summary>
/// 创建错误消息
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public static MessageBox ErrorShow(string message) => new(ResonseCode.Error, message);
/// <summary>
/// 创建消息
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public static MessageBox Show(string message) => new(message);
/// <summary>
/// 创建消息 输出消息和数据
/// </summary>
/// <param name="message"></param>
/// <param name="data"></param>
public static MessageBox Show(string message, object data) => new(message, data);
/// <summary>
/// 创建消息 输出消息和数据
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
/// <returns></returns>
public static MessageBox Show(int code, string message, object? data = null) => new(code, message, data);
/// <summary>
/// 创建消息 输出消息和数据
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
/// <returns></returns>
public static MessageBox Show(ResonseCode code, string message, object? data = null) => new(code, message, data);
}
}

View File

@ -1,74 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.DotNetCore.Base
{
/// <summary>
///
/// </summary>
public class MessageException : Exception
{
/// <summary>
///
/// </summary>
/// <param name="code"></param>
public MessageException(ResonseCode code)
{
Code = (int)code;
Message = "";
}
/// <summary>
///
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public MessageException(ResonseCode code, string message, object? data = null)
{
Code = (int)code;
Message = message;
Data = data;
}
/// <summary>
///
/// </summary>
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public MessageException(int code, string message, object? data = null)
{
Code = code;
Message = message;
Data = data;
}
/// <summary>
///
/// </summary>
/// <param name="message"></param>
/// <param name="data"></param>
public MessageException(string message, object? data = null)
{
Code = 0;
Message = message;
Data = data;
}
/// <summary>
/// 功能执行返回代码
/// </summary>
public int Code { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 数据
/// </summary>
public object? Data { get; set; }
}
}

View File

@ -54,6 +54,11 @@ public enum ResonseCode
/// </summary>
NotFoundRecord = -3,
/// <summary>
/// 数据为null
/// </summary>
NullOrEmpty = -4,
/// <summary>
/// 成功
/// </summary>

View File

@ -17,7 +17,7 @@ namespace HuanMeng.DotNetCore.MiddlewareExtend
return builder
.UseExceptionMiddleware()
.UseExecutionTimeMiddleware()
.UseSignMiddleware()
//.SignBaseMiddleware()
;
}
@ -46,9 +46,9 @@ namespace HuanMeng.DotNetCore.MiddlewareExtend
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseSignMiddleware(this IApplicationBuilder builder)
public static IApplicationBuilder SignBaseMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SignMiddleware>();
return builder.UseMiddleware<SignBaseMiddleware>();
}
}
}

View File

@ -15,11 +15,11 @@ namespace HuanMeng.DotNetCore.MiddlewareExtend
/// <summary>
/// 参数请求加密验证
/// </summary>
public class SignMiddleware
public class SignBaseMiddleware
{
private readonly RequestDelegate _next;
private const string FixedString = "cccc"; // 固定字符串
public SignMiddleware(RequestDelegate next)
public SignBaseMiddleware(RequestDelegate next)
{
_next = next;
}

View File

@ -84,6 +84,33 @@ namespace HuanMeng.DotNetCore.Redis
// 将 RedisValue 转换为 T 类型
return JsonConvert.DeserializeObject<T>(value);
}
/// <summary>
/// 获取一个key的对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public static async Task<T?> StringGetAsync<T>(this IDatabase database, string key)
{
var value = await database.StringGetAsync(key);
// 检查值是否为空
if (!value.HasValue)
{
return default(T);
}
if (typeof(T).IsPrimitive || typeof(T) == typeof(string) || typeof(T) == typeof(decimal))
{
try
{
return (T)Convert.ChangeType(value.ToString(), typeof(T));
}
catch
{
return default; // 或抛出异常,取决于业务需求
}
}
// 将 RedisValue 转换为 T 类型
return JsonConvert.DeserializeObject<T>(value);
}
}
}

View File

@ -18,6 +18,7 @@ public class PhoneNumberValidator
{
return false;
}
return phoneNumberRegex.IsMatch(input);
}
}