diff --git a/src/CloudGaming/Api/CloudGaming.Api/CloudGaming.Api.csproj b/src/CloudGaming/Api/CloudGaming.Api/CloudGaming.Api.csproj
index 567d147..687f39b 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/CloudGaming.Api.csproj
+++ b/src/CloudGaming/Api/CloudGaming.Api/CloudGaming.Api.csproj
@@ -8,6 +8,7 @@
Linux
..\..
True
+ true
diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs
new file mode 100644
index 0000000..9e60b6c
--- /dev/null
+++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs
@@ -0,0 +1,68 @@
+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;
+using HuanMeng.DotNetCore.Base;
+
+using HuanMeng.DotNetCore.Utility;
+
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace CloudGaming.Api.Controllers;
+
+///
+/// 账号管理
+///
+public class AccountController : CloudGamingControllerBase
+{
+ public AccountController(IServiceProvider _serviceProvider) : base(_serviceProvider)
+ {
+ }
+
+ ///
+ /// 发送验证码
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Message("发送成功")]
+ public async Task SendPhoneNumber([FromBody] PhoneNumberRequest phoneNumber)
+ {
+ AccountBLL account = new AccountBLL(ServiceProvider);
+ return await account.SendPhoneNumber(phoneNumber.PhoneNumber);
+ }
+
+ ///
+ /// 登录接口
+ /// 登录数据格式(设备号的目的是用于以后的多设备登录)
+ /// 短信登录:{"phoneNumber":"手机号","verificationCode":"验证码","deviceNumber":"设备号"}
+ /// token登录(请求标头需要带上Authorized的token) {"deviceNumber":"设备号"}
+ ///
+ ///
+ [HttpPost]
+ public async Task LoginAsync([FromBody] BaseLoginParams baseLogin)
+ {
+ AccountBLL account = new AccountBLL(ServiceProvider);
+ return await account.LoginAsync();
+ }
+
+ ///
+ ///
+ ///
+ ///
+ [HttpGet]
+ [Authorize]
+ public async Task GetUserInfo()
+ {
+ return true;
+ }
+}
diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs
index 907168e..eafa2b7 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs
+++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs
@@ -3,6 +3,7 @@ using CloudGaming.Code.Config;
using CloudGaming.DtoModel;
using CloudGaming.GameModel.Db.Db_Ext;
+using HuanMeng.DotNetCore.AttributeExtend;
using HuanMeng.DotNetCore.Base;
using Microsoft.AspNetCore.Mvc;
@@ -24,6 +25,7 @@ namespace CloudGaming.Api.Controllers
///
///
[HttpGet]
+ [Message("发送成功")]
public async Task GetAppConfigAsync()
{
AppConfigBLL appConfigBLL = new AppConfigBLL(ServiceProvider);
diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/GameController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/GameController.cs
index 798b456..4117bce 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/Controllers/GameController.cs
+++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/GameController.cs
@@ -74,5 +74,18 @@ namespace CloudGaming.Api.Controllers
GameBLL gamebll = new GameBLL(this.ServiceProvider);
return gamebll.GameRecommendations(gameId);
}
+ ///
+ /// 游戏搜索
+ ///
+ ///
+ ///
+ [HttpGet]
+ public List GameSearch([FromQuery] string? gameId)
+ {
+
+ GameBLL gamebll = new GameBLL(this.ServiceProvider);
+ return gamebll.GameSearch(gameId);
+ }
+
}
}
diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/HomeController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/HomeController.cs
index 1f6ce5c..d158d86 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/Controllers/HomeController.cs
+++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/HomeController.cs
@@ -8,6 +8,9 @@ using Microsoft.AspNetCore.Mvc;
namespace CloudGaming.Api.Controllers;
+///
+/// 首页
+///
public class HomeController : CloudGamingControllerBase
{
public HomeController(IServiceProvider _serviceProvider) : base(_serviceProvider)
diff --git a/src/CloudGaming/Api/CloudGaming.Api/Dockerfile b/src/CloudGaming/Api/CloudGaming.Api/Dockerfile
index 9f8f60f..68c5cf0 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/Dockerfile
+++ b/src/CloudGaming/Api/CloudGaming.Api/Dockerfile
@@ -4,8 +4,7 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
-EXPOSE 8080
-EXPOSE 8081
+EXPOSE 80
# 此阶段用于生成服务项目
@@ -14,8 +13,10 @@ ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Api/CloudGaming.Api/CloudGaming.Api.csproj", "Api/CloudGaming.Api/"]
COPY ["Code/CloudGaming.Code/CloudGaming.Code.csproj", "Code/CloudGaming.Code/"]
-COPY ["Model/CloudGaming.Model/CloudGaming.Model.csproj", "Model/CloudGaming.Model/"]
+COPY ["Model/CloudGaming.DtoModel/CloudGaming.DtoModel.csproj", "Model/CloudGaming.DtoModel/"]
+COPY ["Model/CloudGaming.GameModel/CloudGaming.GameModel.csproj", "Model/CloudGaming.GameModel/"]
COPY ["Utile/HuanMeng.DotNetCore/HuanMeng.DotNetCore.csproj", "Utile/HuanMeng.DotNetCore/"]
+COPY ["Model/CloudGaming.Model/CloudGaming.Model.csproj", "Model/CloudGaming.Model/"]
RUN dotnet restore "./Api/CloudGaming.Api/CloudGaming.Api.csproj"
COPY . .
WORKDIR "/src/Api/CloudGaming.Api"
diff --git a/src/CloudGaming/Api/CloudGaming.Api/Program.cs b/src/CloudGaming/Api/CloudGaming.Api/Program.cs
index 4265974..0bbf42c 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/Program.cs
+++ b/src/CloudGaming/Api/CloudGaming.Api/Program.cs
@@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Options;
using CloudGaming.GameModel.Db.Db_Ext;
using CloudGaming.Code.MiddlewareExtend;
+using CloudGaming.Code.Filter;
var builder = WebApplication.CreateBuilder(args);
#region 日志
// Add services to the container.
@@ -51,6 +52,7 @@ builder.Services.AddControllers(options =>
{
// 添加自定义的 ResultFilter 到全局过滤器中
options.Filters.Add();
+ options.Filters.Add();
})
.AddNewtonsoftJson(options =>
{
@@ -68,7 +70,9 @@ builder.Services.AddControllers(options =>
//options.SerializerSettings.Converters.Add()
// 其他配置...
});
-builder.Services.AddSingleton();
+//CustomResultFilter
+//builder.Services.AddSingleton();
+
#endregion
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
diff --git a/src/CloudGaming/Api/CloudGaming.Api/appsettings.Development.json b/src/CloudGaming/Api/CloudGaming.Api/appsettings.Development.json
index bb5fb81..1f3aad1 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/appsettings.Development.json
+++ b/src/CloudGaming/Api/CloudGaming.Api/appsettings.Development.json
@@ -5,6 +5,15 @@
"Microsoft.AspNetCore": "Warning"
}
},
+ "AgileConfig": {
+ "appId": "CloudGaming",
+ "secret": "95BB717C61D1ECB0E9FB82C932CC77FF",
+ "nodes": "http://124.220.55.158:94", //多个节点使用逗号分隔
+ "url": "http://124.220.55.158:94",
+ "env": "DEV",
+ "UserName": "admin",
+ "Password": "dbt@com@1234"
+ },
//服务器配置
"Kestrel": {
"Endpoints": {
diff --git a/src/CloudGaming/Api/CloudGaming.Api/appsettings.json b/src/CloudGaming/Api/CloudGaming.Api/appsettings.json
index 9d8e2c3..5cadeec 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/appsettings.json
+++ b/src/CloudGaming/Api/CloudGaming.Api/appsettings.json
@@ -74,7 +74,7 @@
"secret": "95BB717C61D1ECB0E9FB82C932CC77FF",
"nodes": "http://124.220.55.158:94", //多个节点使用逗号分隔
"url": "http://124.220.55.158:94",
- "env": "DEV",
+ "env": "TEST",
"UserName": "admin",
"Password": "dbt@com@1234"
},
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs
new file mode 100644
index 0000000..0b46f8c
--- /dev/null
+++ b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs
@@ -0,0 +1,294 @@
+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;
+
+namespace CloudGaming.Code.Account
+{
+ ///
+ /// 账号操作
+ ///
+ public class AccountBLL : CloudGamingBase
+ {
+ public AccountBLL(IServiceProvider serviceProvider) : base(serviceProvider)
+ {
+
+ }
+
+ ///
+ /// 发送手机号码
+ ///
+ ///
+ ///
+ public async Task SendPhoneNumber(string PhoneNumber)
+ {
+ if (!PhoneNumberValidator.IsPhoneNumber(PhoneNumber))
+ {
+ 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 MessageBox.Show(ResonseCode.PhoneNumberMaxException, "当日发送以达到上限");
+ }
+ var phoneNumberCache = RedisCache.StringGetAsync($"App:sms:{PhoneNumber}");
+ var verificationCode = new Random().Next(1000, 9999).ToString();
+ var sms = AppConfig.AliyunConfig.GetPhoneNumberVerificationService();
+ bool isSend = false;
+ string exMsg = "";
+ try
+ {
+ isSend = await sms.SendVerificationCodeAsync(PhoneNumber, verificationCode);
+ }
+ catch (Exception ex)
+ {
+
+ exMsg = ex.Message;
+ if (exMsg.Length > 200)
+ {
+ exMsg = exMsg.Substring(0, 200);
+ }
+ }
+ if (isSend)
+ {
+ await RedisCache.StringSetAsync($"App:sms:{PhoneNumber}", verificationCode, TimeSpan.FromMinutes(5));
+ }
+
+ T_Sms_Log t_Sms_Log = new T_Sms_Log()
+ {
+ VerificationCode = verificationCode,
+ ErrorMessage = exMsg,
+ PhoneNumber = PhoneNumber,
+ SendStatus = isSend ? 1 : 0,
+ SendTime = DateTime.Now,
+ SendTimeDay = day
+ };
+ Dao.DaoExt.Context.T_Sms_Log.Add(t_Sms_Log);
+ await Dao.DaoExt.Context.SaveChangesAsync();
+ if (!isSend)
+ {
+ throw MessageBox.ErrorShow("发送失败");
+ }
+ return isSend;
+ }
+
+ ///
+ /// 登录接口
+ ///
+ ///
+ public async Task 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>(key);
+ accountUserLoginInfos ??= new List();
+ //创建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 注册用户
+ ///
+ /// 注册新用户或更新现有用户信息
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task 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 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 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
+ }
+}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs
new file mode 100644
index 0000000..5f60f12
--- /dev/null
+++ b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs
@@ -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
+ {
+
+ ///
+ /// 返回对应的登录方式
+ ///
+ ///
+ ///
+ public static IUserAccount? GetUserAccount(string jsonString, CloudGamingBase cloudGamingBase)
+ {
+ JObject jsonObject = JObject.Parse(jsonString);
+ if (AllKeysExistIgnoreCase(jsonObject, "PhoneNumber", "VerificationCode"))
+ {
+ var loginParams = JsonConvert.DeserializeObject(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)));
+ }
+ }
+}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Account/Contract/IUserAccount.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/Contract/IUserAccount.cs
new file mode 100644
index 0000000..413de82
--- /dev/null
+++ b/src/CloudGaming/Code/CloudGaming.Code/Account/Contract/IUserAccount.cs
@@ -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
+{
+ ///
+ /// 登录接口
+ ///
+ public interface IUserAccount
+ {
+
+ ///
+ /// 登录方式
+ ///
+ public int LastLoginType { get; set; }
+
+ ///
+ /// 设备号
+ ///
+ public string DeviceNumber { get; }
+ ///
+ /// 登录
+ ///
+ ///
+ Task LoginAsync();
+
+
+ ///
+ /// 创建账号
+ ///
+ ///
+ ///
+ Task CreateLoginAsync(T_User user);
+
+
+ ///
+ /// 获取用户属性
+ ///
+ ///
+ ///
+ string GetUserDataProperty(UserDataPropertyEnum userDataPropertyEnum);
+ }
+}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Account/Login/PhoneUserLogin.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/Login/PhoneUserLogin.cs
new file mode 100644
index 0000000..ed596f8
--- /dev/null
+++ b/src/CloudGaming/Code/CloudGaming.Code/Account/Login/PhoneUserLogin.cs
@@ -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
+{
+ ///
+ /// 手机号登录
+ ///
+ ///
+ ///
+ public class PhoneUserLogin(PhoneLoginParams loginParams, CloudGamingBase cloudGamingBase) : IUserAccount
+ {
+ public async Task 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;
+ }
+
+ ///
+ /// 创建登录账号
+ ///
+ ///
+ ///
+ 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);
+ }
+
+ ///
+ ///
+ ///
+ public int LastLoginType { get; set; } = 1;
+
+ ///
+ /// 返回登录信息
+ ///
+ ///
+ ///
+ public string GetUserDataProperty(UserDataPropertyEnum userDataPropertyEnum)
+ {
+ if (userDataPropertyEnum == UserDataPropertyEnum.PhoneNum)
+ {
+ return loginParams.PhoneNumber;
+ }
+ return "";
+ }
+
+ ///
+ /// 设备号
+ ///
+ public string DeviceNumber
+ {
+ get
+ {
+ if (loginParams.DeviceNumber.Length > 100)
+ {
+ loginParams.DeviceNumber = loginParams.DeviceNumber.Substring(0, 100);
+ }
+ return loginParams.DeviceNumber;
+ }
+
+
+ }
+ }
+}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AliyunOssConfig.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AliyunOssConfig.cs
deleted file mode 100644
index db5c9bb..0000000
--- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AliyunOssConfig.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace CloudGaming.Code.AppExtend
-{
- public class AliyunOssConfig
- {
- ///
- ///
- ///
- public string AccessKeyId { get; set; }
- ///
- /// 配置环境变量
- ///
- public string AccessKeySecret { get; set; }
- ///
- /// 替换为Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
- ///
- public string EndPoint { get; set; }
- ///
- /// Bucket名称。
- ///
- public string BucketName { get; set; }
-
- ///
- /// 上传路径
- ///
- public string UploadPath { get; set; }
-
- ///
- /// 域名
- ///
- public string? DomainName { get; set; }
-
- ///
- /// 前缀
- ///
- public string ImagePrefix
- {
- get
- {
- return this.DomainName + this.UploadPath;
- }
- }
- }
-}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfig.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfig.cs
index 301b08c..1deee68 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfig.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfig.cs
@@ -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;
+
+///
+/// 项目配置
+///
+public class AppConfig
{
+ public AppConfig() { }
///
- /// 项目配置
+ /// 用户数据库连接字符串
///
- public class AppConfig
+ public string UserConnectionString { get; set; }
+ ///
+ /// 游戏
+ ///
+ public string GameConnectionString { get; set; }
+ ///
+ /// 扩展
+ ///
+ public string ExtConnectionString { get; set; }
+
+ ///
+ /// 手机app配置
+ ///
+ public string PhoneConnectionString { get; set; }
+
+ ///
+ /// redis连接字符串
+ ///
+ public string RedisConnectionString { get; set; }
+
+ ///
+ /// 域名
+ ///
+ public string DomainName { get; set; }
+ ///
+ /// 标识
+ ///
+ public string Identifier { get; set; }
+ ///
+ /// 名称
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 默认语言
+ ///
+ public string DefaultLanguage { get; set; }
+ ///
+ /// 租户
+ ///
+ public Guid TenantId { get; set; }
+ ///
+ /// 项目支付数据
+ ///
+ //public PaymentModel? Payment { get; set; }
+
+ ///
+ /// oss阿里云配置
+ ///
+ public AliyunConfig AliyunConfig { get; set; }
+
+ ///
+ /// 用户默认配置
+ ///
+ public UserConfig UserConfig { get; set; }
+
+ ///
+ /// 获取数据库连接字符串
+ ///
+ /// user,game,ext,phone
+ ///
+ ///
+ public string GetConnectionString(AppDataBaseType appDataBaseType)
{
- public AppConfig() { }
- ///
- /// 用户数据库连接字符串
- ///
- public string UserConnectionString { get; set; }
- ///
- /// 游戏
- ///
- public string GameConnectionString { get; set; }
- ///
- /// 扩展
- ///
- public string ExtConnectionString { get; set; }
-
- ///
- /// 手机app配置
- ///
- public string PhoneConnectionString { get; set; }
-
- ///
- /// redis连接字符串
- ///
- public string RedisConnectionString { get; set; }
-
- ///
- /// 域名
- ///
- public string DomainName { get; set; }
- ///
- /// 标识
- ///
- public string Identifier { get; set; }
- ///
- /// 名称
- ///
- public string Name { get; set; }
-
- ///
- /// 默认语言
- ///
- public string DefaultLanguage { get; set; }
- ///
- /// 租户
- ///
- public Guid TenantId { get; set; }
- ///
- /// 项目支付数据
- ///
- //public PaymentModel? Payment { get; set; }
-
- ///
- /// oss阿里云配置
- ///
- public AliyunOssConfig AliyunConfig { get; set; }
-
-
- ///
- /// 获取数据库连接字符串
- ///
- /// user,game,ext,phone
- ///
- ///
- 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("数据库连接字符串不存在");
}
}
-
- ///
- /// 数据库选项
- ///
-
- public enum AppDataBaseType
- {
- ///
- /// 用户数据库
- ///
- User,
- ///
- /// 游戏数据库
- ///
- Game,
- ///
- /// 扩展数据库
- ///
- Ext,
- ///
- /// app数据库
- ///
- App
- }
+}
+
+///
+/// 数据库选项
+///
+
+public enum AppDataBaseType
+{
+ ///
+ /// 用户数据库
+ ///
+ User,
+ ///
+ /// 游戏数据库
+ ///
+ Game,
+ ///
+ /// 扩展数据库
+ ///
+ Ext,
+ ///
+ /// app数据库
+ ///
+ App
}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs
index ae0e434..92115ad 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfigurationExtend.cs
@@ -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;
}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/Config/AliyunConfig.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/Config/AliyunConfig.cs
new file mode 100644
index 0000000..fb7a6a0
--- /dev/null
+++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/Config/AliyunConfig.cs
@@ -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;
+
+
+///
+/// 阿里云配置
+///
+public class AliyunConfig
+{
+ ///
+ ///
+ ///
+ public string AccessKeyId { get; set; }
+ ///
+ /// 配置环境变量
+ ///
+ public string AccessKeySecret { get; set; }
+
+ #region 阿里云OSS配置
+ ///
+ /// 替换为Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
+ ///
+ public string EndPoint { get; set; }
+ ///
+ /// Bucket名称。
+ ///
+ public string BucketName { get; set; }
+
+ ///
+ /// 上传路径
+ ///
+ public string UploadPath { get; set; }
+
+ ///
+ /// 域名
+ ///
+ public string? DomainName { get; set; }
+
+ ///
+ /// 前缀
+ ///
+ public string ImagePrefix
+ {
+ get
+ {
+ return this.DomainName; //+ this.UploadPath
+ }
+ }
+
+ #endregion
+
+ ///
+ /// 短信签名名称
+ ///
+ public string SmsSignName { get; set; }
+
+ ///
+ /// string 短信模板配置
+ ///
+ public string SmsTemplateCode { get; set; }
+
+}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/Config/UserConfig.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/Config/UserConfig.cs
new file mode 100644
index 0000000..7d047b6
--- /dev/null
+++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/Config/UserConfig.cs
@@ -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;
+
+///
+/// 用户默认配置
+///
+public class UserConfig
+{
+ ///
+ /// 用户默认头像
+ ///
+ public string UserIconUrl { get; set; }
+ ///
+ /// 用户默认昵称
+ ///
+ public string NickName { get; set; }
+
+ ///
+ /// 用户最大登录设备
+ ///
+ public int MaxDeviceCount { get; set; }
+}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomObjectResultExecutor.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomObjectResultExecutor.cs
deleted file mode 100644
index 45d4d7d..0000000
--- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomObjectResultExecutor.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using Org.BouncyCastle.Asn1.Ocsp;
-
-using System;
-using System.Buffers;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace CloudGaming.Code.AppExtend
-{
- public class CustomObjectResultExecutor : ObjectResultExecutor
- {
- private readonly IHttpContextAccessor _httpContextAccessor;
-
- public CustomObjectResultExecutor(OutputFormatterSelector formatterSelector, IHttpResponseStreamWriterFactory writerFactory, ILoggerFactory loggerFactory, IOptions mvcOptions):base(formatterSelector, writerFactory, loggerFactory, mvcOptions)
-
- {
- //_httpContextAccessor = httpContextAccessor;
- }
-
- public override Task ExecuteAsync(ActionContext context, ObjectResult result)
- {
- var httpContext = _httpContextAccessor.HttpContext;
- var user = httpContext.User.Identity.IsAuthenticated ? httpContext.User.Identity.Name : "Anonymous";
-
- //// 动态修改返回的结果数据(示例:修改 Message 字段)
- //if (result.Value is ResponseData responseData)
- //{
- // if (user == "admin")
- // {
- // responseData.Message += " (admin)";
- // }
- //}
-
- return base.ExecuteAsync(context, result);
- }
- }
-}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs
deleted file mode 100644
index 42fd786..0000000
--- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using CloudGaming.Code.DataAccess;
-using CloudGaming.GameModel.Db.Db_Ext;
-
-using HuanMeng.DotNetCore.AttributeExtend;
-using HuanMeng.DotNetCore.Base;
-using HuanMeng.DotNetCore.Utility;
-
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.AspNetCore.Mvc.Filters;
-using Microsoft.Identity.Client;
-
-using Swashbuckle.AspNetCore.SwaggerGen;
-
-using System;
-using System.Collections;
-using System.Collections.Specialized;
-using System.Diagnostics;
-using System.Net;
-using System.Reflection;
-
-namespace CloudGaming.Code.AppExtend
-{
- ///
- ///
- ///
- public class CustomResultFilter : IResultFilter
- {
- private readonly IHttpContextAccessor _httpContextAccessor;
- private readonly IServiceProvider _serviceProvider;
- private readonly AppConfig _appConfig;
- public CustomResultFilter(IHttpContextAccessor httpContextAccessor, AppConfig appConfig, IServiceProvider serviceProvider)
- {
- _httpContextAccessor = httpContextAccessor;
- _appConfig = appConfig;
- _serviceProvider = serviceProvider;
- }
-
- public void OnResultExecuting(ResultExecutingContext context)
- {
- // 获取当前的 HttpContext
- var httpContext = context.HttpContext;
- var path = httpContext.Request.Path.Value ?? "";
- var apiPrefix = path.Replace('/', '.').TrimStart('.');
- var sw = Stopwatch.StartNew();
- //_appConfig.
- CloudGamingBase cloudGamingBase = new CloudGamingBase(_serviceProvider);
- // 获取当前用户的信息
- var user = httpContext.User.Identity.IsAuthenticated ? httpContext.User.Identity.Name : "Anonymous";
- //Dictionary keyValuePairs = new Dictionary();
- if (context.Result is ObjectResult objectResult && objectResult.Value != null)
- {
- var x = objectResult.Value.GetType();
- object? value = null;
- if (!x.FullName.Contains("HuanMeng.DotNetCore.Base.BaseResponse"))
- {
- BaseResponse