添加实名认证接口

This commit is contained in:
zpc 2024-11-16 03:44:18 +08:00
parent 2b1ff84d4f
commit 248ac1fe07
22 changed files with 1054 additions and 98 deletions

View File

@ -1,3 +1,13 @@
# CloudGaming
云游戏
云游戏
# CloudGaming
云游戏
## 发布
cd /disk/CodeManage/CloudGaming/src/CloudGaming
docker build -t cloudgaming:dev-0.0.4 -f Api/CloudGaming.Api/Dockerfile .
docker run -d -p 81:80 cloudgaming:dev-0.0.4

View File

@ -68,4 +68,16 @@ public class AccountController : CloudGamingControllerBase
AccountBLL account = new AccountBLL(ServiceProvider);
return await account.GetUserInfo();
}
/// <summary>
/// 获取用户信息
/// </summary>
/// <returns></returns>
[HttpPost]
[Authorize]
public async Task<BaseResponse<bool>> RealAuthentication([FromBody] UserRealAuthenticationRequest authenticationRequest)
{
AccountBLL account = new AccountBLL(ServiceProvider);
return await account.RealAuthentication(authenticationRequest.UserName, authenticationRequest.IdCard, authenticationRequest.DeviceNumber);
}
}

View File

@ -1,6 +1,7 @@
using Alipay.EasySDK.Kernel;
using CloudGaming.Code.Account.Contract;
using CloudGaming.Code.Contract;
using CloudGaming.Code.Sms;
using CloudGaming.DtoModel.Account;
using CloudGaming.DtoModel.Account.Login;
@ -15,6 +16,8 @@ using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Collections.Generic;
using System.Linq;
@ -130,9 +133,9 @@ namespace CloudGaming.Code.Account
userCurrency = new List<T_User_Currency>();
}
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));
//创建用户缓存
await AccountExtend.LogUserInfoCahceAsync(RedisCache, user, userData, userCurrencyDic);
//创建jwt登录
var jwt = GenerateJwtToken(user);
var accountLogIn = new AccountLogInResponse
@ -251,7 +254,8 @@ namespace CloudGaming.Code.Account
UpdateAt = DateTime.Now,
PhoneNum = account.GetUserDataProperty(UserDataPropertyEnum.PhoneNum),
UserId = userId,
Email = account.GetUserDataProperty(UserDataPropertyEnum.Email)
Email = account.GetUserDataProperty(UserDataPropertyEnum.Email),
DeviceNumber = account.DeviceNumber
};
await Dao.DaoUser.Context.T_User_Data.AddAsync(userData);
await Dao.DaoUser.Context.SaveChangesAsync();
@ -362,12 +366,8 @@ namespace CloudGaming.Code.Account
#endregion
public string GetUserInfoRedisKey(int userId)
{
return $"user:userInfo:{userId}";
}
/// <summary>
///
/// 获取用户信息
/// </summary>
/// <returns></returns>
public async Task<UserInfoDto> GetUserInfo()
@ -377,81 +377,230 @@ namespace CloudGaming.Code.Account
{
throw MessageBox.Show(ResonseCode.NotFoundRecord, "未找到用户");
}
string key = GetUserInfoRedisKey(userId);
var userInfo = await RedisCache.StringGetAsync<UserInfo>(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));
}
UserInfoCache? userInfo = await GetUserInfoCache();
UserInfoDto userInfoDto = Mapper.Map<UserInfoDto>(userInfo);
if (!string.IsNullOrEmpty(userInfoDto.UserName))
{
userInfoDto.UserName = userInfoDto.UserName.Length <= 2
? userInfoDto.UserName.Substring(0, 1) + "*"
: userInfoDto.UserName.Substring(0, 1) + "*" + userInfoDto.UserName.Substring(userInfoDto.UserName.Length - 1);
}
// 将用户身份证号设置成 "前四位*后四位"
if (!string.IsNullOrEmpty(userInfoDto.IdCard) && userInfoDto.IdCard.Length >= 8)
{
userInfo.IdCard = userInfoDto.IdCard.Substring(0, 4) + "*********" + userInfoDto.IdCard.Substring(userInfoDto.IdCard.Length - 4);
}
return userInfoDto;
}
/// <summary>
/// 加载用户缓存
/// </summary>
/// <param name="key"></param>
/// <param name="user"></param>
/// <param name="userData"></param>
/// <param name="userCurrency"></param>
/// <returns></returns>
private UserInfo LoadUserInfo(T_User? user, T_User_Data? userData, Dictionary<UserCurrencyType, T_User_Currency> 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;
}
#region
/// <summary>
/// 实名认证
/// </summary>
/// <returns></returns>
public async Task<bool> RealAuthentication(string userName, string idCard)
public async Task<BaseResponse<bool>> RealAuthentication(string userName, string idCard, string deviceNumber)
{
return true;
// 参数校验
ValidateParameters(userName, idCard);
// 检查用户信息和状态
CheckUserRealNameStatus(userName, idCard);
// 获取用户
var user = await Dao.DaoUser.Context.T_User.FirstOrDefaultAsync(it => it.Id == _UserId);
if (user == null)
{
throw CreateException(ResonseCode.NotFoundRecord, "用户不存在");
}
// 实名认证接口验证
var idCardVerify = this.GetIdCardVerify();
var (isv, msg) = await idCardVerify.IdCardVerify(userName, idCard);
if (!isv)
{
await LogRealAuthenticationFailure(userName, idCard, deviceNumber, msg);
throw CreateException(ResonseCode.NotFoundRecord, "身份证号错误");
}
// 更新用户实名认证状态
UpdateUserRealNameStatus(user, userName, idCard);
// 发放实名认证奖励
var rewardMessage = await GrantRewardsIfEligible(deviceNumber);
// 保存日志
await LogRealAuthenticationSuccess(userName, idCard, deviceNumber, rewardMessage);
// 更新缓存
await UpdateUserCache(userName, idCard);
return new BaseResponse<bool>(0, $"认证成功!{rewardMessage}") { }; ;
}
/// <summary>
/// 校验参数
/// </summary>
private void ValidateParameters(string userName, string idCard)
{
if (string.IsNullOrEmpty(userName))
{
throw CreateException(ResonseCode.ParamError, "用户名为空");
}
if (string.IsNullOrEmpty(idCard) || !OtherExtensions.ValidateIDCard(idCard))
{
throw CreateException(ResonseCode.ParamError, "身份证号错误");
}
}
/// <summary>
/// 检查用户实名认证状态
/// </summary>
private void CheckUserRealNameStatus(string userName, string idCard)
{
//判断用户是否实名认证过,并且不等于未成年人
if (UserInfo.IsRealName && !UserInfo.IsJuveniles)
{
throw MessageBox.Show(0, "此账号已实名认证成功,无需重复实名");
}
if (UserInfo.RealNameDateTimeLast != null && DateTime.Now.Subtract((UserInfo.RealNameDateTimeLast ?? DateTime.MinValue)).TotalSeconds < 10)
{
throw MessageBox.Show(ResonseCode.Error, "两次绑定身份证号时间间隔太短,请稍后再绑定~");
}
if (UserInfo.IdCard == idCard && UserInfo.UserName == userName)
{
throw MessageBox.Show(0, "此账号已实名认证成功,无需重复验证");
}
if (UserInfo.RealAuthentCount > 10)
{
throw MessageBox.Show(0, "此账号今日实名认证次数已到达上限");
}
}
/// <summary>
/// 更新用户实名认证状态
/// </summary>
private void UpdateUserRealNameStatus(T_User user, string userName, string idCard)
{
var (isValid, age, _, _) = OtherExtensions.GetIDCardBirthdayAgeSex(idCard);
user.UserName = userName;
user.IDCard = idCard;
if (isValid)
{
UserInfo.IsJuveniles = age < 18;
user.UserRealNameStatus = UserInfo.IsJuveniles ? 2 : 1;
}
UserInfo.IsRealName = true;
UserInfo.RealNameDateTimeLast = DateTime.Now;
UserInfo.RealAuthentCount++;
}
/// <summary>
/// 发放实名认证奖励
/// </summary>
private async Task<string> GrantRewardsIfEligible(string deviceNumber)
{
if (string.IsNullOrEmpty(deviceNumber))
{
deviceNumber = UserInfo.DeviceNumber;
}
var hasUserReward = await Dao.DaoUser.Context.T_User_LimitActionLog
.AnyAsync(it => it.UserId == _UserId && it.ActionType == (int)UserActionTypeEnum.ActionType.);
if (hasUserReward)
{
return "用户已经领取过奖励,不再发放奖励";
}
var hasDeviceReward = await Dao.DaoUser.Context.T_User_LimitActionLog
.AnyAsync(it => it.DeviceNumber == deviceNumber && it.ActionType == (int)UserActionTypeEnum.ActionType.);
if (!hasDeviceReward)
{
var limitActionLog = new T_User_LimitActionLog
{
CreateTime = DateTime.Now,
CreateTimeDay = int.Parse(DateTime.Now.ToString("yyyyMMdd")),
ActionType = (int)UserActionTypeEnum.ActionType.,
DeviceNumber = deviceNumber,
UserId = _UserId,
Ip = HttpContextAccessor.HttpContext.GetClientIpAddress()
};
await Dao.DaoUser.Context.T_User_LimitActionLog.AddAsync(limitActionLog);
await Dao.DaoUser.Context.SaveChangesAsync();
return "奖励已经发送,钻石*10";
}
return "用户设备号重复,不发放奖励";
}
/// <summary>
/// 记录实名认证失败日志
/// </summary>
private async Task LogRealAuthenticationFailure(string userName, string idCard, string deviceNumber, string msg)
{
if (msg.Length > 100)
{
msg = msg.Substring(0, 100);
}
var log = new T_User_RealAuthentication_Log
{
CreateTime = DateTime.Now,
DeviceNumber = deviceNumber,
IdCard = idCard,
UserId = _UserId,
UserName = userName,
IsRewards = false,
RealResults = msg,
Message = "认证失败"
};
await Dao.DaoExt.Context.T_User_RealAuthentication_Log.AddAsync(log);
await Dao.DaoExt.Context.SaveChangesAsync();
UserInfo.RealNameDateTimeLast = DateTime.Now;
UserInfo.RealAuthentCount++;
await this.SaveUserInfoCacheChangesAsync();
}
/// <summary>
/// 记录实名认证成功日志
/// </summary>
private async Task LogRealAuthenticationSuccess(string userName, string idCard, string deviceNumber, string message)
{
var log = new T_User_RealAuthentication_Log
{
CreateTime = DateTime.Now,
DeviceNumber = deviceNumber,
IdCard = idCard,
UserId = _UserId,
UserName = userName,
IsRewards = message.Contains("奖励已经发送"),
RealResults = "认证成功",
Message = message
};
await Dao.DaoExt.Context.T_User_RealAuthentication_Log.AddAsync(log);
await Dao.DaoExt.Context.SaveChangesAsync();
}
/// <summary>
/// 更新用户缓存
/// </summary>
private async Task UpdateUserCache(string userName, string idCard)
{
UserInfo.UserName = userName;
UserInfo.IdCard = idCard;
UserInfo.IsRealName = true;
UserInfo.RealNameDateTimeLast = DateTime.Now;
UserInfo.RealAuthentCount++;
await this.SaveUserInfoCacheChangesAsync();
}
#endregion
}
}

View File

@ -1,11 +1,18 @@
using CloudGaming.Code.Account.Contract;
using CloudGaming.Code.Account.Login;
using CloudGaming.Code.DataAccess;
using CloudGaming.DtoModel.Account.Login;
using CloudGaming.DtoModel.Account.User;
using HuanMeng.DotNetCore.Redis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using StackExchange.Redis;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.Linq;
@ -66,5 +73,151 @@ namespace CloudGaming.Code.Account
}
return 0;
}
/// <summary>
/// 用户缓存的key
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public static string GetUserInfoRedisKey(int userId)
{
return $"user:userInfo:{userId}";
}
/// <summary>
///
/// </summary>
/// <param name="userInfoCache"></param>
/// <param name="userId"></param>
/// <param name="cloudGamingBase"></param>
/// <returns></returns>
public static async Task<UserInfoCache?> GetUserInfo(this UserInfoCache userInfoCache, int userId, CloudGamingBase cloudGamingBase)
{
userInfoCache = await GetUserInfo(userId, cloudGamingBase) ?? new UserInfoCache();
return userInfoCache;
}
/// <summary>
/// 获取用户信息
/// </summary>
/// <param name="userId"></param>
/// <param name="cloudGamingBase"></param>
/// <returns></returns>
public static async Task<UserInfoCache?> GetUserInfo(int userId, CloudGamingBase cloudGamingBase)
{
if (userId == 0)
{
return new UserInfoCache();
}
string key = GetUserInfoRedisKey(userId);
var userInfo = await cloudGamingBase.RedisCache.StringGetAsync<UserInfoCache>(key);
if (userInfo == null)
{
var Dao = cloudGamingBase.Dao;
userInfo = new UserInfoCache() { };
//用户信息
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 cloudGamingBase.RedisCache.StringSetAsync(key, userInfo, TimeSpan.FromHours(1));
}
return userInfo;
}
/// <summary>
/// 设置用户信息
/// </summary>
/// <param name="database"></param>
/// <param name="user"></param>
/// <param name="userData"></param>
/// <param name="userCurrency"></param>
/// <returns></returns>
public static async Task<UserInfoCache?> LogUserInfoCahceAsync(IDatabase database, T_User user, T_User_Data? userData = null, Dictionary<UserCurrencyType, T_User_Currency> userCurrency = null)
{
var key = GetUserInfoRedisKey(user.Id);
var userInfo = new UserInfoCache() { };
LoadUserInfo(userInfo, user, userData, userCurrency);
await database.StringSetAsync(key, userInfo, TimeSpan.FromHours(1));
return userInfo;
}
/// <summary>
/// 加载用户缓存
/// </summary>
/// <param name="userInfo"></param>
/// <param name="user"></param>
/// <param name="userData"></param>
/// <param name="userCurrency"></param>
/// <returns></returns>
public static UserInfoCache LoadUserInfo(this UserInfoCache userInfo, T_User? user = null, T_User_Data? userData = null, Dictionary<UserCurrencyType, T_User_Currency> userCurrency = null)
{
if (userInfo == null)
{
userInfo = new UserInfoCache();
}
if (user != null)
{
userInfo.NickName = user.NickName;
userInfo.UserId = user.Id;
userInfo.UserIcon = user.UserIconUrl;
userInfo.IsRealName = user.UserRealNameStatus > 0;
userInfo.IsJuveniles = user.UserRealNameStatus == 2;
userInfo.UserName = user.UserName ?? "";
userInfo.IdCard = user.IDCard ?? "";
}
if (userData != null)
{
userInfo.PhoneNum = userData?.PhoneNum ?? "";
userInfo.Email = userData?.Email ?? "";
userInfo.DeviceNumber = userData?.DeviceNumber ?? "";
}
userInfo.TotalGamingTime = 0;
if (userCurrency != null)
{
userInfo.Diamond = (int)userCurrency.GetUserCurrency(UserCurrencyType.);
}
return userInfo;
}
/// <summary>
/// 加载用户缓存
/// </summary>
/// <param name="userInfo"></param>
/// <param name="user"></param>
/// <param name="userData"></param>
/// <param name="userCurrency"></param>
/// <returns></returns>
public static UserInfoCache LoadUserInfo(T_User? user = null, T_User_Data? userData = null, Dictionary<UserCurrencyType, T_User_Currency> userCurrency = null)
{
var userInfo = new UserInfoCache();
return LoadUserInfo(userInfo, user, userData, userCurrency);
}
/// <summary>
/// 保存用户缓存
/// </summary>
/// <param name="cloudGamingBase"></param>
/// <returns></returns>
public static async Task<UserInfoCache> SaveUserInfoCacheChangesAsync(this CloudGamingBase cloudGamingBase)
{
var userInfo = cloudGamingBase.UserInfo;
var key = GetUserInfoRedisKey(cloudGamingBase.UserInfo.UserId);
await cloudGamingBase.RedisCache.StringSetAsync(key, userInfo, TimeSpan.FromHours(1));
return userInfo;
}
}
}

View File

@ -0,0 +1,105 @@
using CloudGaming.Code.Contract;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tea;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace CloudGaming.Code.Aliyun
{
/// <summary>
/// 阿里云身份证号验证 AlibabaExtend
/// </summary>
public class AlibabaIdCardVerify(AliyunConfig aliyunConfig) : IIdCardVerify
{
/// <term><b>Description:</b></term>
/// <description>
/// <para>使用AK&amp;SK初始化账号Client</para>
/// </description>
///
/// <returns>
/// Client
/// </returns>
///
/// <term><b>Exception:</b></term>
/// Exception
public AlibabaCloud.SDK.Cloudauth20190307.Client CreateClient()
{
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。
// 建议使用更安全的 STS 方式更多鉴权访问方式请参见https://help.aliyun.com/document_detail/378671.html。
AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config
{
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
AccessKeyId = aliyunConfig.AccessKeyId,
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
AccessKeySecret = aliyunConfig.AccessKeySecret,
};
// Endpoint 请参考 https://api.aliyun.com/product/Cloudauth
config.Endpoint = "cloudauth.aliyuncs.com";
return new AlibabaCloud.SDK.Cloudauth20190307.Client(config);
}
/// <summary>
///
/// </summary>
/// <param name="userName"></param>
/// <param name="idCard"></param>
/// <returns></returns>
public async Task<(bool isVerify, string msg)> IdCardVerify(string userName, string idCard)
{
AlibabaCloud.SDK.Cloudauth20190307.Client client = CreateClient();
AlibabaCloud.SDK.Cloudauth20190307.Models.Id2MetaVerifyRequest id2MetaVerifyRequest = new AlibabaCloud.SDK.Cloudauth20190307.Models.Id2MetaVerifyRequest
{
ParamType = "normal",
IdentifyNum = idCard,
UserName = userName,
};
AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
try
{
// 复制代码运行请自行打印 API 的返回值
var obj = await client.Id2MetaVerifyWithOptionsAsync(id2MetaVerifyRequest, runtime);
if (obj.Body.ResultObject.BizCode == "1")
{
return (true, obj.Body.ResultObject.BizCode);
}
else
{
return (false, obj.Body.ResultObject.BizCode == "2" ? "核验不一致" : $"{obj.Body.ResultObject.BizCode}_查无记录");
}
}
catch (TeaException error)
{
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
Console.WriteLine(error.Message);
// 诊断地址
Console.WriteLine(error.Data["Recommend"]);
AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
return (false, error.Message);
}
catch (Exception _error)
{
TeaException error = new TeaException(new Dictionary<string, object>
{
{ "message", _error.Message }
});
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
Console.WriteLine(error.Message);
// 诊断地址
Console.WriteLine(error.Data["Recommend"]);
AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
return (false, error.Message);
}
}
}
}

View File

@ -1,5 +1,6 @@
using AutoMapper;
using CloudGaming.Code.Account;
using CloudGaming.Code.Cache;
using CloudGaming.Code.Config;
using CloudGaming.Code.DataAccess;
@ -249,15 +250,15 @@ namespace CloudGaming.Code.AppExtend
#endregion
#region
private RequestUserInfo? _userInfo;
private RequestUserInfo? _requestUserInfo;
/// <summary>
/// 用户信息
/// </summary>
public RequestUserInfo UserInfo
public RequestUserInfo RequestUserInfo
{
get
{
if (_userInfo == null)
if (_requestUserInfo == null)
{
var accessToken = HttpContextAccessor.HttpContext.Request.Headers.GetAuthorization();
if (!string.IsNullOrEmpty(accessToken))
@ -276,7 +277,7 @@ namespace CloudGaming.Code.AppExtend
}
var nickName = principal.FindFirst("NickName")?.Value;
var userId = int.Parse(userIdStr);
this._userInfo = new RequestUserInfo()
this._requestUserInfo = new RequestUserInfo()
{
UserId = userId,
NickName = nickName
@ -284,7 +285,7 @@ namespace CloudGaming.Code.AppExtend
}
catch (Exception)
{
_userInfo = new RequestUserInfo()
_requestUserInfo = new RequestUserInfo()
{
UserId = 0
};
@ -292,14 +293,14 @@ namespace CloudGaming.Code.AppExtend
}
else
{
_userInfo = new RequestUserInfo()
_requestUserInfo = new RequestUserInfo()
{
UserId = 0
};
}
}
return _userInfo;
return _requestUserInfo;
}
}
@ -310,9 +311,51 @@ namespace CloudGaming.Code.AppExtend
{
get
{
return UserInfo?.UserId ?? 0;
return RequestUserInfo?.UserId ?? 0;
}
}
private UserInfoCache _userInfo;
/// <summary>
/// 用户信息
/// </summary>
public UserInfoCache UserInfo
{
get
{
if (_userInfo == null)
{
if (_UserId == 0)
{
_userInfo = new UserInfoCache();
}
_userInfo = _userInfo.GetUserInfo(_UserId, this).Result ?? new UserInfoCache();
}
return _userInfo;
}
}
public async Task<UserInfoCache> GetUserInfoCache()
{
if (_UserId == 0)
{
_userInfo = new UserInfoCache();
}
if (_userInfo == null)
{
_userInfo = await _userInfo.GetUserInfo(_UserId, this) ?? new UserInfoCache();
}
return _userInfo;
}
#endregion
/// <summary>
/// 创建异常
/// </summary>
public Exception CreateException(ResonseCode errorCode, string message)
{
return MessageBox.Show(errorCode, message);
}
}
}

View File

@ -10,6 +10,7 @@
<ItemGroup>
<PackageReference Include="AgileConfig.Client" Version="1.7.3" />
<PackageReference Include="AlibabaCloud.SDK.Cloudauth20190307" Version="3.2.0" />
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="3.1.0" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Bogus" Version="35.6.1" />

View File

@ -0,0 +1,38 @@
using CloudGaming.Code.Sms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CloudGaming.Code.Aliyun;
namespace CloudGaming.Code.Contract
{
/// <summary>
///
/// </summary>
public static class CloudGamingExtend
{
/// <summary>
/// 获取短信
/// </summary>
/// <param name="aliyunOssConfig"></param>
/// <returns></returns>
public static IPhoneNumberVerificationService GetPhoneNumberVerificationService(this AliyunConfig aliyunOssConfig)
{
return new AlibabaPhoneNumberVerificationService(aliyunOssConfig);
}
/// <summary>
///
/// </summary>
/// <param name="aliyunOssConfig"></param>
/// <returns></returns>
public static IIdCardVerify GetIdCardVerify(this CloudGamingBase cloudGamingBase)
{
return new AlibabaIdCardVerify(cloudGamingBase.AppConfig.AliyunConfig);
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.Contract
{
/// <summary>
///
/// </summary>
public interface IIdCardVerify
{
/// <summary>
/// 身份证号验证
/// </summary>
/// <param name="userName">姓名</param>
/// <param name="idCard">身份证号</param>
/// <returns></returns>
Task<(bool isVerify, string msg)> IdCardVerify(string userName, string idCard);
}
}

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Code.Sms.Contract
namespace CloudGaming.Code.Contract
{
/// <summary>
/// 发送手机短信

View File

@ -1,4 +1,6 @@
using CloudGaming.Code.Sms.Contract;
using CloudGaming.Code.Contract;
using System;
using System.Collections.Generic;
@ -18,7 +20,7 @@ namespace CloudGaming.Code.Sms
/// <term><b>Description:</b></term>
/// <description>
/// <para>使用AK&amp;SK初始化账号Client</para>
/// <para>使用AK&amp;SK初始化账号Client</para>
/// </description>
///
/// <returns>
@ -102,15 +104,7 @@ namespace CloudGaming.Code.Sms
/// </summary>
public static class SmsExtend
{
/// <summary>
/// 获取短信
/// </summary>
/// <param name="aliyunOssConfig"></param>
/// <returns></returns>
public static IPhoneNumberVerificationService GetPhoneNumberVerificationService(this AliyunConfig aliyunOssConfig)
{
return new AlibabaPhoneNumberVerificationService(aliyunOssConfig);
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.DtoModel.Account.User
{
/// <summary>
///
/// </summary>
public class UserActionTypeEnum
{
/// <summary>
/// 行为类型
/// </summary>
public enum ActionType
{
/// <summary>
/// 新人礼包
/// </summary>
= 1,
/// <summary>
/// 新人第二天登录礼包
/// </summary>
= 2,
/// <summary>
/// 实名认证
/// </summary>
= 3,
= 4
}
}
}

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.User
{
/// <summary>
/// 用户缓存
/// </summary>
public class UserInfoCache : UserInfo
{
/// <summary>
/// 最后一次实名认证时间
/// </summary>
public DateTime? RealNameDateTimeLast { get; set; }
/// <summary>
/// 实名认证次数
/// </summary>
public int RealAuthentCount { get; set; }
/// <summary>
/// 设备号
/// </summary>
public string DeviceNumber { get; set; }
}
}

View File

@ -11,7 +11,7 @@ namespace CloudGaming.DtoModel.Account.User
/// <summary>
/// 用户信息
/// </summary>
[AutoMap(typeof(UserInfo))]
[AutoMap(typeof(UserInfoCache))]
public class UserInfoDto : UserInfo
{
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.DtoModel.Account
{
/// <summary>
/// 用户实名认证
/// </summary>
public class UserRealAuthenticationRequest
{
/// <summary>
/// 姓名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 身份证号
/// </summary>
public string IdCard { get; set; }
/// <summary>
/// 设备号
/// </summary>
public string DeviceNumber { get; set; }
}
}

View File

@ -64,6 +64,11 @@ public partial class CloudGamingCBTContext : DbContext
/// </summary>
public virtual DbSet<T_User_Login_Log> T_User_Login_Log { get; set; }
/// <summary>
/// 用户实名认证记录表
/// </summary>
public virtual DbSet<T_User_RealAuthentication_Log> T_User_RealAuthentication_Log { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{// => optionsBuilder.UseSqlServer("Server=192.168.195.6;Database=CloudGamingCBT;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;");
}
@ -205,6 +210,45 @@ public partial class CloudGamingCBTContext : DbContext
});
modelBuilder.Entity<T_User_RealAuthentication_Log>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK_T_USER_REALAUTHENTICATIONLO");
entity.ToTable(tb => tb.HasComment("用户实名认证记录表"));
entity.HasIndex(e => e.UserId, "UserId").IsDescending();
entity.Property(e => e.Id).HasComment("主键Id");
entity.Property(e => e.CreateTime)
.HasDefaultValueSql("(getdate())")
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.DeviceNumber)
.HasMaxLength(100)
.HasComment("设备号");
entity.Property(e => e.IdCard)
.HasMaxLength(20)
.HasDefaultValue("")
.HasComment("身份证号")
.UseCollation("Chinese_PRC_CI_AS");
entity.Property(e => e.IsRewards).HasComment("是否发放奖励");
entity.Property(e => e.Message)
.HasMaxLength(100)
.HasComment("扩展消息");
entity.Property(e => e.RealResults)
.HasMaxLength(100)
.HasComment("认证结果");
entity.Property(e => e.UserId)
.HasDefaultValueSql("('')")
.HasComment("用户id");
entity.Property(e => e.UserName)
.HasMaxLength(30)
.HasDefaultValue("")
.HasComment("姓名")
.UseCollation("Chinese_PRC_CI_AS");
});
OnModelCreatingPartial(modelBuilder);
}

View File

@ -0,0 +1,56 @@
using System;
namespace CloudGaming.GameModel.Db.Db_Ext;
/// <summary>
/// 用户实名认证记录表
/// </summary>
public partial class T_User_RealAuthentication_Log
{
public T_User_RealAuthentication_Log() { }
/// <summary>
/// 主键Id
/// </summary>
public virtual int Id { get; set; }
/// <summary>
/// 用户id
/// </summary>
public virtual int UserId { get; set; }
/// <summary>
/// 姓名
/// </summary>
public virtual string UserName { get; set; } = null!;
/// <summary>
/// 身份证号
/// </summary>
public virtual string IdCard { get; set; } = null!;
/// <summary>
/// 创建时间
/// </summary>
public virtual DateTime CreateTime { get; set; }
/// <summary>
/// 设备号
/// </summary>
public virtual string? DeviceNumber { get; set; }
/// <summary>
/// 是否发放奖励
/// </summary>
public virtual bool IsRewards { get; set; }
/// <summary>
/// 认证结果
/// </summary>
public virtual string? RealResults { get; set; }
/// <summary>
/// 扩展消息
/// </summary>
public virtual string? Message { get; set; }
}

View File

@ -63,6 +63,11 @@ public partial class CloudGamingUserContext : MultiTenantDbContext//DbContext
/// </summary>
public virtual DbSet<T_User_IntentOrder> T_User_IntentOrder { get; set; }
/// <summary>
/// 用户设备限制行为日志表
/// </summary>
public virtual DbSet<T_User_LimitActionLog> T_User_LimitActionLog { get; set; }
/// <summary>
/// 小程序登录表
/// </summary>
@ -228,6 +233,9 @@ public partial class CloudGamingUserContext : MultiTenantDbContext//DbContext
entity.Property(e => e.CreateAt)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.DeviceNumber)
.HasMaxLength(255)
.HasComment("设备号");
entity.Property(e => e.Email)
.HasMaxLength(255)
.HasComment("邮箱");
@ -292,6 +300,41 @@ public partial class CloudGamingUserContext : MultiTenantDbContext//DbContext
}
});
modelBuilder.Entity<T_User_LimitActionLog>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK_T_USER_LIMITACTIONLOG");
entity.ToTable(tb => tb.HasComment("用户设备限制行为日志表"));
entity.Property(e => e.Id).HasComment("自增");
entity.Property(e => e.ActionId)
.HasMaxLength(100)
.HasComment("行为参数")
.UseCollation("Chinese_PRC_CI_AS");
entity.Property(e => e.ActionType).HasComment("行为类型1新人礼包2新人第二天登录礼包3实名认证奖励");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.CreateTimeDay).HasComment("创建时间,天");
entity.Property(e => e.DeviceNumber)
.HasMaxLength(100)
.HasComment("设备号");
entity.Property(e => e.Extend1)
.HasMaxLength(200)
.HasComment("扩展字段")
.UseCollation("Chinese_PRC_CI_AS");
entity.Property(e => e.Ip)
.HasMaxLength(100)
.HasComment("请求Ip")
.UseCollation("Chinese_PRC_CI_AS");
entity.Property(e => e.UserId).HasComment("用户Id");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_User_MiniProgram_Account>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_User_M__3214EC073889A8B9");

View File

@ -43,4 +43,9 @@ public partial class T_User_Data: MultiTenantEntity
/// 修改时间
/// </summary>
public virtual DateTime UpdateAt { get; set; }
/// <summary>
/// 设备号
/// </summary>
public virtual string? DeviceNumber { get; set; }
}

View File

@ -0,0 +1,56 @@
using System;
namespace CloudGaming.Model.DbSqlServer.Db_User;
/// <summary>
/// 用户设备限制行为日志表
/// </summary>
public partial class T_User_LimitActionLog: MultiTenantEntity
{
public T_User_LimitActionLog() { }
/// <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; }
/// <summary>
/// 行为类型1新人礼包2新人第二天登录礼包3实名认证奖励
/// </summary>
public virtual int ActionType { get; set; }
/// <summary>
/// 行为参数
/// </summary>
public virtual string? ActionId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public virtual DateTime CreateTime { get; set; }
/// <summary>
/// 创建时间,天
/// </summary>
public virtual int CreateTimeDay { get; set; }
/// <summary>
/// 设备号
/// </summary>
public virtual string? DeviceNumber { get; set; }
/// <summary>
/// 扩展字段
/// </summary>
public virtual string? Extend1 { get; set; }
}

View File

@ -10,7 +10,7 @@ namespace HuanMeng.DotNetCore.Utility
public static class DateTimeExtensions
{
/// <summary>
/// 获取时间戳,秒
/// 获取时间戳,秒
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>

View File

@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace HuanMeng.DotNetCore.Utility
{
/// <summary>
/// 其它扩展类
/// </summary>
public static class OtherExtensions
{
/// <summary>
/// 验证身份证号是否正确
/// </summary>
/// <param name="idNumber"></param>
/// <returns></returns>
public static bool ValidateIDCard(string idNumber)
{
if (string.IsNullOrEmpty(idNumber))
{
return false;
}
// 验证长度
if (idNumber.Length != 18)
{
return false;
}
// 验证格式
Regex regex = new Regex(@"^\d{17}(\d|X)$");
if (!regex.IsMatch(idNumber))
{
return false;
}
// 验证校验码
return ValidateCheckDigit(idNumber);
}
/// <summary>
/// 验证校验码
/// </summary>
/// <param name="idNumber"></param>
/// <returns></returns>
private static bool ValidateCheckDigit(string idNumber)
{
// 加权因子
int[] weights = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
// 校验码
char[] checkDigits = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };
int sum = 0;
for (int i = 0; i < 17; i++)
{
sum += (idNumber[i] - '0') * weights[i];
}
int mod = sum % 11;
return idNumber[17] == checkDigits[mod];
}
/// <summary>
/// 根据身份证号计算年龄、性别、生日
/// </summary>
/// <param name="identityCard">身份证号</param>
/// <returns></returns>
public static (bool verify, int age, string sex, string birthday) GetIDCardBirthdayAgeSex(string identityCard)
{
var birthday = "";
var age = 0;
var sex = "";
if (string.IsNullOrEmpty(identityCard))
{
return (false, 0, "", "");
}
else
{
if (identityCard.Length != 15 && identityCard.Length != 18)//身份证号码只能为15位或18位其它不合法
{
return (false, 0, "", "");
}
}
birthday = "";
string strSex = string.Empty;
if (identityCard.Length == 18)//处理18位的身份证号码从号码中得到生日和性别代码
{
birthday = identityCard.Substring(6, 4) + "-" + identityCard.Substring(10, 2) + "-" + identityCard.Substring(12, 2);
strSex = identityCard.Substring(14, 3);
}
if (identityCard.Length == 15)
{
birthday = "19" + identityCard.Substring(6, 2) + "-" + identityCard.Substring(8, 2) + "-" + identityCard.Substring(10, 2);
strSex = identityCard.Substring(12, 3);
}
age = CalculateAge(birthday);//根据生日计算年龄
if (int.Parse(strSex) % 2 == 0)//性别代码为偶数是女性奇数为男性
{
sex = "女";
}
else
{
sex = "男";
}
return (true, age, sex, birthday);
}
/// <summary>
/// 根据出生日期,计算精确的年龄
/// </summary>
/// <param name="birthDate">生日</param>
/// <returns></returns>
public static int CalculateAge(string birthDay)
{
DateTime birthDate = DateTime.Parse(birthDay);
DateTime nowDateTime = DateTime.Now;
int age = nowDateTime.Year - birthDate.Year;
//再考虑月、天的因素
if (nowDateTime.Month < birthDate.Month || (nowDateTime.Month == birthDate.Month && nowDateTime.Day < birthDate.Day))
{
age--;
}
return age;
}
}
}