diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs index 1575c37..f151cfa 100644 --- a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs +++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AccountController.cs @@ -7,6 +7,7 @@ using CloudGaming.Code.DataAccess; using CloudGaming.Code.MiddlewareExtend; using CloudGaming.DtoModel.Account; using CloudGaming.DtoModel.Account.Login; +using CloudGaming.DtoModel.Account.User; using CloudGaming.GameModel.Db.Db_Ext; using HuanMeng.DotNetCore.AttributeExtend; @@ -57,13 +58,14 @@ public class AccountController : CloudGamingControllerBase } /// - /// + /// 获取用户信息 /// /// [HttpGet] [Authorize] - public async Task GetUserInfo() + public async Task GetUserInfo() { - return true; + AccountBLL account = new AccountBLL(ServiceProvider); + return await account.GetUserInfo(); } } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs index 658bfac..e1777a7 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs @@ -4,11 +4,15 @@ using CloudGaming.Code.Account.Contract; using CloudGaming.Code.Sms; using CloudGaming.DtoModel.Account; using CloudGaming.DtoModel.Account.Login; +using CloudGaming.DtoModel.Account.User; using HuanMeng.DotNetCore.JwtInfrastructure; using HuanMeng.DotNetCore.Redis; using HuanMeng.DotNetCore.Utility; +using Microsoft.EntityFrameworkCore.Metadata.Internal; + +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -119,6 +123,16 @@ namespace CloudGaming.Code.Account var user = await RegisterOrUpdateUserAsync(userId, account, ip); //注册用户详细信息 var userData = await EnsureUserDataExistsAsync(user.Id, account); + //用户货币 + var userCurrency = await EnsureUserCurrencyExistsAsync(user.Id); + if (userCurrency == null) + { + userCurrency = new List(); + } + var userCurrencyDic = userCurrency.ToDictionary(it => (UserCurrencyType)it.CurrencyType); + var userInfoKey = GetUserInfoRedisKey(user.Id); + var userInfo = LoadUserInfo(user, userData, userCurrencyDic); + await RedisCache.StringSetAsync(userInfoKey, userInfo, TimeSpan.FromHours(1)); //创建jwt登录 var jwt = GenerateJwtToken(user); var accountLogIn = new AccountLogInResponse @@ -161,8 +175,6 @@ namespace CloudGaming.Code.Account private async Task ManageDeviceCacheAsync(int userId, string currentTokenMd5, List deviceList) { - - // 获取用户当前所有的登录缓存key var existingKeys = await RedisServerCache.ScanKeysAsync($"user:login:{userId}:*"); @@ -211,7 +223,8 @@ namespace CloudGaming.Code.Account State = 0, UserIconUrl = AppConfig.UserConfig.UserIconUrl, NickName = $"{AppConfig.UserConfig.NickName}{new Random().Next(1000, 9999)}", - Ip = ip + Ip = ip, + IsRealName = false }; await Dao.DaoUser.Context.T_User.AddAsync(user); await Dao.DaoUser.Context.SaveChangesAsync(); @@ -222,7 +235,7 @@ namespace CloudGaming.Code.Account user.UpdatedAt = DateTime.Now; user.Ip = ip; await Dao.DaoUser.Context.SaveChangesAsync(); - + return user; } @@ -245,6 +258,28 @@ namespace CloudGaming.Code.Account } return userData; } + // 确保用户数据存在 + private async Task> EnsureUserCurrencyExistsAsync(int userId) + { + var userCurrencys = await Dao.DaoUser.Context.T_User_Currency.Where(it => it.UserId == userId).ToListAsync(); + if (userCurrencys == null || userCurrencys.Count == 0) + { + userCurrencys ??= new List(); + var userCurrency = new T_User_Currency + { + CreateAt = DateTime.Now, + CurrencyMoney = 0, + CurrencyName = UserCurrencyType.钻石.ToString(), + CurrencyType = (int)UserCurrencyType.钻石, + UpdateAt = DateTime.Now, + UserId = userId + }; + await Dao.DaoUser.Context.T_User_Currency.AddAsync(userCurrency); + await Dao.DaoUser.Context.SaveChangesAsync(); + userCurrencys.Add(userCurrency); + } + return userCurrencys; + } // 生成JWT令牌 private JwtAuthResult GenerateJwtToken(T_User user) @@ -327,5 +362,96 @@ namespace CloudGaming.Code.Account #endregion + public string GetUserInfoRedisKey(int userId) + { + return $"user:userInfo:{userId}"; + } + /// + /// + /// + /// + public async Task GetUserInfo() + { + var userId = _UserId; + if (userId == 0) + { + throw MessageBox.Show(ResonseCode.NotFoundRecord, "未找到用户"); + } + string key = GetUserInfoRedisKey(userId); + var userInfo = await RedisCache.StringGetAsync(key); + if (userInfo == null) + { + userInfo = new UserInfo() { }; + //用户信息 + var user = await Dao.DaoUser.Context.T_User.FirstOrDefaultAsync(it => it.Id == userId); + //用户扩展信息 + var userData = await Dao.DaoUser.Context.T_User_Data.FirstOrDefaultAsync(it => it.UserId == userId); + //用户货币 + var userCurrency = await Dao.DaoUser.Context.T_User_Currency.Where(it => it.UserId == userId).ToDictionaryAsync(it => (UserCurrencyType)it.CurrencyType); + if (user == null) + { + throw MessageBox.Show(ResonseCode.NotFoundRecord, "未找到用户信息"); + } + if (userData == null) + { + throw MessageBox.Show(ResonseCode.NotFoundRecord, "未找到用户扩展信息"); + } + + userInfo = LoadUserInfo(user, userData, userCurrency); + await RedisCache.StringSetAsync(key, userInfo, TimeSpan.FromHours(1)); + } + UserInfoDto userInfoDto = Mapper.Map(userInfo); + return userInfoDto; + } + + /// + /// 加载用户缓存 + /// + /// + /// + /// + /// + /// + private UserInfo LoadUserInfo(T_User? user, T_User_Data? userData, Dictionary userCurrency) + { + var userInfo = new UserInfo() { }; + userInfo.NickName = user.NickName; + userInfo.UserId = user.Id; + userInfo.UserIcon = user.UserIconUrl; + userInfo.IsRealName = user.UserRealNameStatus > 0; + userInfo.IsJuveniles = false; + userInfo.UserName = ""; + userInfo.IdCard = ""; + if (userInfo.IsRealName) + { + userInfo.IsJuveniles = user.UserRealNameStatus == 2; + if (!string.IsNullOrEmpty(user.UserName)) + { + // 将用户昵称设置成 "陈*风" 或 "陈*"(如果只有两个字符) + userInfo.UserName = user.UserName.Length <= 2 + ? user.UserName.Substring(0, 1) + "*" + : user.UserName.Substring(0, 1) + "*" + user.UserName.Substring(user.UserName.Length - 1); + } + // 将用户身份证号设置成 "前四位*后四位" + if (!string.IsNullOrEmpty(user.IDCard) && user.IDCard.Length >= 8) + { + userInfo.IdCard = user.IDCard.Substring(0, 4) + "*********" + user.IDCard.Substring(user.IDCard.Length - 4); + } + } + userInfo.TotalGamingTime = 0; + userInfo.PhoneNum = userData?.PhoneNum ?? ""; + userInfo.Email = userData?.Email ?? ""; + userInfo.Diamond = (int)userCurrency.GetUserCurrency(UserCurrencyType.钻石); + return userInfo; + } + + /// + /// 实名认证 + /// + /// + public async Task RealAuthentication(string userName, string idCard) + { + return true; + } } } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs index ca42d6a..8eb425b 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs @@ -1,6 +1,7 @@ using CloudGaming.Code.Account.Contract; using CloudGaming.Code.Account.Login; using CloudGaming.DtoModel.Account.Login; +using CloudGaming.DtoModel.Account.User; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -47,5 +48,23 @@ namespace CloudGaming.Code.Account var propertie = jsonObject.Properties(); return keysToCheck.All(key => propertie.Any(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase))); } + + /// + /// 获取用户货币 + /// + /// + /// + /// + public static decimal GetUserCurrency(this Dictionary curreny, UserCurrencyType userCurrencyType) + { + if (curreny != null) + { + if (curreny.TryGetValue(userCurrencyType, out var _currency)) + { + return _currency.CurrencyMoney; + } + } + return 0; + } } } diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CloudGamingBase.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CloudGamingBase.cs index ec1a2c5..e231d32 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CloudGamingBase.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CloudGamingBase.cs @@ -3,12 +3,15 @@ using AutoMapper; using CloudGaming.Code.Cache; using CloudGaming.Code.Config; using CloudGaming.Code.DataAccess; +using CloudGaming.DtoModel.Account.User; using HuanMeng.DotNetCore.JwtInfrastructure.Interface; using HuanMeng.DotNetCore.Redis; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; using StackExchange.Redis; @@ -244,5 +247,72 @@ namespace CloudGaming.Code.AppExtend } } #endregion + + #region 用户信息 + private RequestUserInfo? _userInfo; + /// + /// 用户信息 + /// + public RequestUserInfo UserInfo + { + get + { + if (_userInfo == null) + { + var accessToken = HttpContextAccessor.HttpContext.Request.Headers.GetAuthorization(); + if (!string.IsNullOrEmpty(accessToken)) + { + try + { + var (principal, jwtToken) = JwtAuthManager.DecodeJwtToken(accessToken); + if (jwtToken == null)//|| !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256Signature) + { + throw new SecurityTokenException("无效的token"); + } + var userIdStr = principal.FindFirst("UserId")?.Value; + if (string.IsNullOrEmpty(userIdStr)) + { + throw new SecurityTokenException("无效的token"); + } + var nickName = principal.FindFirst("NickName")?.Value; + var userId = int.Parse(userIdStr); + this._userInfo = new RequestUserInfo() + { + UserId = userId, + NickName = nickName + }; + } + catch (Exception) + { + _userInfo = new RequestUserInfo() + { + UserId = 0 + }; + } + } + else + { + _userInfo = new RequestUserInfo() + { + UserId = 0 + }; + } + } + + return _userInfo; + } + } + + /// + /// 用户Id + /// + public int _UserId + { + get + { + return UserInfo?.UserId ?? 0; + } + } + #endregion } } diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/RequestUserInfo.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/RequestUserInfo.cs new file mode 100644 index 0000000..802ce63 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/RequestUserInfo.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.Account.User +{ + /// + /// 请求标头携带的用户信息 + /// + public class RequestUserInfo + { + public RequestUserInfo() { } + /// + /// 昵称 + /// + public string NickName { get; set; } + + /// + /// 用户id + /// + public int UserId { get; set; } + } +} diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserCurrencyType.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserCurrencyType.cs new file mode 100644 index 0000000..f112f38 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserCurrencyType.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.Account.User +{ + /// 用户货币类型 + /// + public enum UserCurrencyType + { + /// + /// 钻石 + /// + 钻石 = 0 + } +} diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfo.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfo.cs new file mode 100644 index 0000000..106dccb --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfo.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.Account.User +{ + /// + /// 用户信息 + /// + public class UserInfo + { + /// + /// 用户昵称 + /// + public string NickName { get; set; } + + /// + /// 用户id + /// + public int UserId { get; set; } + /// + /// 用户手机号 + /// + public string PhoneNum { get; set; } + + /// + /// 用户邮箱 + /// + public string Email { get; set; } + + /// + /// 用户头像 + /// + public string UserIcon { get; set; } + + /// + /// 用户钻石 + /// + public int Diamond { get; set; } + + /// + /// 总游玩时间(分钟) + /// + public int TotalGamingTime { get; set; } + + /// + /// 用户是否实名认证 + /// + public bool IsRealName { get; set; } + + /// + /// 是否未成年 + /// + public bool IsJuveniles { get; set; } + + /// + /// 实名认证名称 + /// + public string UserName { get; set; } + + /// + /// 身份证号 + /// + public string IdCard { get; set; } + } +} diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfoDto.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfoDto.cs new file mode 100644 index 0000000..1d9e8c6 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Account/User/UserInfoDto.cs @@ -0,0 +1,18 @@ +using AutoMapper; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.Account.User +{ + /// + /// 用户信息 + /// + [AutoMap(typeof(UserInfo))] + public class UserInfoDto : UserInfo + { + } +} diff --git a/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_User/CloudGamingUserContext.cs b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_User/CloudGamingUserContext.cs index 2d0b8c2..53f6d01 100644 --- a/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_User/CloudGamingUserContext.cs +++ b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_User/CloudGamingUserContext.cs @@ -134,6 +134,7 @@ public partial class CloudGamingUserContext : MultiTenantDbContext//DbContext .HasMaxLength(100) .HasComment("姓名") .UseCollation("Chinese_PRC_CI_AS"); + entity.Property(e => e.UserRealNameStatus).HasComment("用户实名认证状态0未认证,1已整整,2未成年"); //添加全局筛选器 if (this.TenantInfo != null) { diff --git a/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_User/T_User.cs b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_User/T_User.cs index c1295b7..4442c07 100644 --- a/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_User/T_User.cs +++ b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_User/T_User.cs @@ -78,4 +78,9 @@ public partial class T_User: MultiTenantEntity /// 是否是测试账号 /// public virtual bool? IsTest { get; set; } + + /// + /// 用户实名认证状态0未认证,1已整整,2未成年 + /// + public virtual int UserRealNameStatus { get; set; } } diff --git a/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs b/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs index 54f59a9..3521ddb 100644 --- a/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs +++ b/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs @@ -157,6 +157,19 @@ namespace HuanMeng.DotNetCore.Redis // 将 RedisValue 转换为 T 类型 return JsonConvert.DeserializeObject(value); } + + /// + /// 数据存放在redis + /// + /// + /// + /// + /// + /// + public static async Task StringSetAsync(this IDatabase database, string key, object value, TimeSpan? expiry) + { + return await database.StringSetAsync(key, (value == null ? "" : JsonConvert.SerializeObject(value)), expiry, When.Always); + } /// /// 获取一个key的对象 ///