diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs
index 723b9c8..9e60b6c 100644
--- a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs
+++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs
@@ -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);
}
+
+ ///
+ /// 登录接口
+ /// 登录数据格式(设备号的目的是用于以后的多设备登录)
+ /// 短信登录:{"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/Code/CloudGaming.Code/Account/AccountBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs
index d7ec67e..0b46f8c 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs
@@ -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;
}
+
+ ///
+ /// 登录接口
+ ///
+ ///
+ 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/AliyunConfig.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AliyunConfig.cs
deleted file mode 100644
index 25f87fa..0000000
--- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AliyunConfig.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace CloudGaming.Code.AppExtend
-{
- ///
- /// 阿里云配置
- ///
- 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/AppConfig.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppConfig.cs
index 70d9c8f..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 AliyunConfig 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/JwtTokenManageExtension.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/JwtTokenManageExtension.cs
index c47534b..b5f26aa 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/JwtTokenManageExtension.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/JwtTokenManageExtension.cs
@@ -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();
+ //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();
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs
index ee1b59e..504bb07 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs
@@ -29,6 +29,7 @@ namespace CloudGaming.Code.Config
IsAuthRealName = true
};
appConfigDto.IsChecking = IsChecking;
+ appConfigDto.SignKey = AppConfig.TenantId.ToString("N");
return appConfigDto;
}
diff --git a/src/CloudGaming/Code/CloudGaming.Code/Filter/CustomExceptionFilter.cs b/src/CloudGaming/Code/CloudGaming.Code/Filter/CustomExceptionFilter.cs
index acf9489..773e4e8 100644
--- a/src/CloudGaming/Code/CloudGaming.Code/Filter/CustomExceptionFilter.cs
+++ b/src/CloudGaming/Code/CloudGaming.Code/Filter/CustomExceptionFilter.cs
@@ -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