合并代码
This commit is contained in:
commit
c89d729bf2
|
|
@ -151,6 +151,7 @@ var app = builder.Build();
|
|||
// app.UseSwagger();
|
||||
// app.UseSwaggerUI();
|
||||
//}
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
|
|
@ -165,6 +166,7 @@ app.UseSwaggerUI(c =>
|
|||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
//注册身份验证中间件
|
||||
app.UseAuthorization();
|
||||
//数据库中间件
|
||||
app.UseMultiTenant();
|
||||
|
|
|
|||
|
|
@ -126,13 +126,11 @@ namespace CloudGaming.Code.Account
|
|||
Token = jwt.AccessToken,
|
||||
UserId = user.Id,
|
||||
};
|
||||
//创建设备号
|
||||
var dev = await ManageUserDevicesAsync(user, account, jwt.AccessToken);
|
||||
var key = $"user:login:{user.Id}";
|
||||
//获取登录的设备
|
||||
var (deviceList, currentDevice) = await ManageUserDevicesAsync(user, account, jwt.AccessToken);
|
||||
// 管理设备和Redis缓存
|
||||
await ManageDeviceCacheAsync(user.Id, currentDevice.TokenMd5, deviceList);
|
||||
|
||||
//创建redis缓存
|
||||
await RedisCache.StringSetAsync(key, $"1", TimeSpan.FromHours(1));
|
||||
//accountUserLoginInfos.Add(new AccountUserLoginInfo());
|
||||
T_User_Login_Log login_Log = new T_User_Login_Log()
|
||||
{
|
||||
Channel = this.AppRequestInfo.Channel,
|
||||
|
|
@ -151,6 +149,42 @@ namespace CloudGaming.Code.Account
|
|||
return accountLogIn;
|
||||
}
|
||||
#region 注册用户
|
||||
|
||||
/// <summary>
|
||||
/// 设备Redis缓存管理方法
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="currentTokenMd5"></param>
|
||||
/// <param name="deviceList"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ManageDeviceCacheAsync(int userId, string currentTokenMd5, List<T_User_Token> deviceList)
|
||||
{
|
||||
|
||||
|
||||
|
||||
// 获取用户当前所有的登录缓存key
|
||||
var existingKeys = await RedisServerCache.ScanKeysAsync($"user:login:{userId}:*");
|
||||
|
||||
if (existingKeys != null && existingKeys.Count > 0)
|
||||
{
|
||||
// 查找和移除不在当前设备列表中的旧设备
|
||||
var activeKeys = deviceList.Select(dev => $"user:login:{userId}:{dev.TokenMd5}").ToHashSet();
|
||||
|
||||
foreach (var key in existingKeys)
|
||||
{
|
||||
if (!activeKeys.Contains(key))
|
||||
{
|
||||
// 将无效设备状态标记为过期
|
||||
await RedisCache.StringSetAsync(key, "0", TimeSpan.FromMinutes(10));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 构建当前设备的Redis key
|
||||
var currentDeviceKey = $"user:login:{userId}:{currentTokenMd5}";
|
||||
// 创建当前设备的缓存记录
|
||||
await RedisCache.StringSetAsync(currentDeviceKey, "1", TimeSpan.FromHours(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册新用户或更新现有用户信息
|
||||
/// </summary>
|
||||
|
|
@ -220,7 +254,7 @@ namespace CloudGaming.Code.Account
|
|||
}
|
||||
|
||||
// 管理用户设备
|
||||
private async Task<List<T_User_Token>> ManageUserDevicesAsync(T_User user, IUserAccount account, string accessToken)
|
||||
private async Task<(List<T_User_Token>, T_User_Token)> ManageUserDevicesAsync(T_User user, IUserAccount account, string accessToken)
|
||||
{
|
||||
var currentTime = DateTime.Now;
|
||||
var dev = string.IsNullOrEmpty(account.DeviceNumber)
|
||||
|
|
@ -274,7 +308,7 @@ namespace CloudGaming.Code.Account
|
|||
}
|
||||
|
||||
await Dao.DaoUser.Context.SaveChangesAsync();
|
||||
return userLoginList;
|
||||
return (userLoginList, existingDevice);
|
||||
}
|
||||
|
||||
// 更新设备令牌信息
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace CloudGaming.Code.Account.Login
|
|||
throw MessageBox.Show(ResonseCode.ParamError, "验证码不能为空");
|
||||
}
|
||||
//判断是否是测试账号
|
||||
if (!loginParams.PhoneNumber.Contains("999999999") && loginParams.VerificationCode == "1112")
|
||||
if (!loginParams.PhoneNumber.Contains("99999999") && loginParams.VerificationCode == "1112")
|
||||
{
|
||||
if (!PhoneNumberValidator.IsPhoneNumber(loginParams.PhoneNumber))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using AgileConfig.Client;
|
||||
|
||||
using CloudGaming.Code.DataAccess;
|
||||
using CloudGaming.Code.DataAccess.MultiTenantUtil;
|
||||
|
||||
using HuanMeng.DotNetCore.CacheHelper;
|
||||
|
|
@ -148,6 +149,16 @@ namespace CloudGaming.Code.AppExtend
|
|||
{
|
||||
return RedisConnection.GetRedis(appConfig.RedisConnectionString);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取Dao
|
||||
/// </summary>
|
||||
/// <param name="appConfig"></param>
|
||||
/// <returns></returns>
|
||||
public static DAO GetDAO(this IServiceProvider serviceProvider)
|
||||
{
|
||||
return new DAO(serviceProvider);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
|||
|
|
@ -169,6 +169,21 @@ namespace CloudGaming.Code.AppExtend
|
|||
return _redis;
|
||||
}
|
||||
}
|
||||
private IServer _redisServer;
|
||||
/// <summary>
|
||||
/// 数据库查询
|
||||
/// </summary>
|
||||
public IServer RedisServerCache
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_redisServer == null)
|
||||
{
|
||||
_redisServer = RedisConnection.GetServer(AppConfig.RedisConnectionString);
|
||||
}
|
||||
return _redisServer;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 缓存
|
||||
|
|
@ -223,7 +238,7 @@ namespace CloudGaming.Code.AppExtend
|
|||
isChecking = new AppConfigBLL(this._serviceProvider).GetAppIsChecking();
|
||||
RedisCache.StringSet(key, isChecking, new TimeSpan(1, 0, 0));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return isChecking ?? false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ namespace CloudGaming.Code.AppExtend
|
|||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
}).AddJwtBearer(options =>
|
||||
{
|
||||
|
||||
options.RequireHttpsMetadata = true;
|
||||
options.SaveToken = true;
|
||||
//调试使用
|
||||
|
|
@ -70,20 +71,62 @@ namespace CloudGaming.Code.AppExtend
|
|||
{
|
||||
OnTokenValidated = async context =>
|
||||
{
|
||||
var userId = context.Principal.FindFirst("userId")?.Value;
|
||||
if (userId == null || true)
|
||||
|
||||
var token = context.Request.Headers.GetAuthorization();
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
context.Fail("Token missing userId claim.");
|
||||
context.Fail("非法请求接口");
|
||||
return;
|
||||
}
|
||||
var _userId = context.Principal.FindFirst("userId")?.Value;
|
||||
int userId = 0;
|
||||
if (_userId == null && !int.TryParse(_userId, out userId))
|
||||
{
|
||||
context.Fail("请求标头错误");
|
||||
return;
|
||||
}
|
||||
var tokenMd5 = MD5Encryption.ComputeMD5Hash(token);
|
||||
var appConfig = context.HttpContext.RequestServices.GetRequiredService<AppConfig>();
|
||||
var host = context.Request.Host.Host;
|
||||
var app = AppConfigurationExtend.GetAppConfig(host);
|
||||
if (app == null)
|
||||
{
|
||||
context.Fail("未配置租户");
|
||||
return;
|
||||
}
|
||||
var redis = app.GetRedisDataBase();
|
||||
var isUserExpire = await redis.StringGetAsync($"user:login:{_userId}:{tokenMd5}");
|
||||
|
||||
var isUserExpireStatus = isUserExpire.ToString();
|
||||
if (string.IsNullOrEmpty(isUserExpireStatus))
|
||||
{
|
||||
//再次去数据库中验证
|
||||
//IServiceProvider
|
||||
var _serviceProvider = context.HttpContext.RequestServices.GetRequiredService<IServiceProvider>();
|
||||
var dao = _serviceProvider.GetDAO();
|
||||
var c = await dao.DaoUser.Context.T_User_Token.Where(it => it.UserId == userId && it.TokenMd5 == tokenMd5).CountAsync();
|
||||
if (c <= 0)
|
||||
{
|
||||
//添加过期信息
|
||||
await redis.StringSetAsync($"user:login:{_userId}:{tokenMd5}", "0", TimeSpan.FromMinutes(15));
|
||||
//app.get
|
||||
context.Fail("用户状态错误");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
isUserExpireStatus = "1";
|
||||
//添加过期信息
|
||||
await redis.StringSetAsync($"user:login:{_userId}:{tokenMd5}", "1", TimeSpan.FromMinutes(30));
|
||||
}
|
||||
}
|
||||
if (isUserExpireStatus == "0")
|
||||
{
|
||||
//设备被顶掉
|
||||
context.Fail("用户在其它设备登录");
|
||||
return;
|
||||
}
|
||||
|
||||
//// 你可以调用数据库或其他服务来验证用户状态
|
||||
//var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
|
||||
//var user = await userService.GetUserByIdAsync(userId);
|
||||
//if (user == null || !user.IsActive)
|
||||
//{
|
||||
// context.Fail("User is inactive or not found.");
|
||||
//}
|
||||
},
|
||||
// 处理认证失败的事件
|
||||
OnAuthenticationFailed = context =>
|
||||
|
|
|
|||
|
|
@ -7,17 +7,20 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Newtonsoft.Json;
|
||||
//var jsopn = JsonConvert.SerializeObject(new PhoneLoginParams());
|
||||
//Server=192.168.1.17;Database=CloudGamingUser;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;
|
||||
var optionsBuilder = new DbContextOptionsBuilder<CloudGamingPhoneContext>();
|
||||
var option = optionsBuilder.UseSqlServer("Server=192.168.195.6;Database=CloudGamingPhone;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;").Options;
|
||||
CloudGamingPhoneContext cloudGamingPhoneContext = new CloudGamingPhoneContext(option);
|
||||
//cloudGamingPhoneContext.Database.EnsureCreated();
|
||||
var x = cloudGamingPhoneContext.T_Epg_Cfg.Count();
|
||||
var ccc = cloudGamingPhoneContext.T_Epg_Cfg.ToList();
|
||||
Console.WriteLine("查询" + x.ToString());
|
||||
Console.ReadKey();
|
||||
//var optionsBuilder = new DbContextOptionsBuilder<CloudGamingPhoneContext>();
|
||||
//var option = optionsBuilder.UseSqlServer("Server=192.168.195.6;Database=CloudGamingPhone;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;").Options;
|
||||
//CloudGamingPhoneContext cloudGamingPhoneContext = new CloudGamingPhoneContext(option);
|
||||
////cloudGamingPhoneContext.Database.EnsureCreated();
|
||||
//var x = cloudGamingPhoneContext.T_GameCBT.Count();
|
||||
//var ccc = cloudGamingPhoneContext.T_Epg_Cfg.ToList();
|
||||
//Console.WriteLine("查询" + x.ToString());
|
||||
//Console.ReadKey();
|
||||
//Server=192.168.1.17;Database=CloudGamingPhone;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;
|
||||
//var optionsBuilder1 = new DbContextOptionsBuilder<CloudGamingUserContext>();
|
||||
//var option1 = optionsBuilder1.UseSqlServer("Server=192.168.1.17;Database=CloudGamingUser;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;").Options;
|
||||
//CloudGamingUserContext cloud = new CloudGamingUserContext(option1);
|
||||
var optionsBuilder1 = new DbContextOptionsBuilder<CloudGamingUserContext>();
|
||||
var option1 = optionsBuilder1.UseSqlServer("Server=192.168.195.6;Database=CloudGamingUser;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;").Options;
|
||||
CloudGamingUserContext cloud = new CloudGamingUserContext(option1);
|
||||
var xxx = cloud.T_User.Count();
|
||||
Console.WriteLine("查询" + xxx.ToString());
|
||||
Console.ReadKey();
|
||||
//cloud.Database.EnsureCreated();
|
||||
//cloud.Database.
|
||||
|
|
@ -65,8 +65,8 @@ public partial class CloudGamingCBTContext : DbContext
|
|||
public virtual DbSet<T_User_Login_Log> T_User_Login_Log { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
=> optionsBuilder.UseSqlServer("Server=192.168.1.17;Database=CloudGamingCBT;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;");
|
||||
|
||||
{// => optionsBuilder.UseSqlServer("Server=192.168.195.6;Database=CloudGamingCBT;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;");
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<T_App_Config>(entity =>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
|
@ -71,6 +71,7 @@ public partial class CloudGamingGameContext : DbContext
|
|||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{// => optionsBuilder.UseSqlServer("Server=192.168.195.6;Database=CloudGamingGame;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;");
|
||||
//optionsBuilder.uses
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@ dotnet ef dbcontext scaffold "Server=192.168.195.6;Database=CloudGamingGame;User
|
|||
--Ext
|
||||
dotnet ef dbcontext scaffold "Server=192.168.1.17;Database=CloudGamingCBT;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;" Microsoft.EntityFrameworkCore.SqlServer -o Db/Db_Ext/ --use-database-names --no-pluralize --force
|
||||
内网穿透
|
||||
dotnet ef dbcontext scaffold "Server=192.168.195.6;Database=CloudGamingGame;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;" Microsoft.EntityFrameworkCore.SqlServer -o Db/Db_Game/ --use-database-names --no-pluralize --force
|
||||
dotnet ef dbcontext scaffold "Server=192.168.195.6;Database=CloudGamingCBT;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;" Microsoft.EntityFrameworkCore.SqlServer -o Db/Db_Ext/ --use-database-names --no-pluralize --force
|
||||
```
|
||||
|
|
@ -147,6 +147,7 @@ public partial class CloudGamingPhoneContext : MultiTenantDbContext//DbContext
|
|||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
// => optionsBuilder.UseSqlServer("Server=192.168.195.6;Database=CloudGamingPhone;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;");
|
||||
{
|
||||
optionsBuilder.UseSqlServer("Server=192.168.195.6;Database=CloudGamingPhone;User Id=sa;Password=Dbt@com@123;TrustServerCertificate=true;");
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.Identity.Client;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
|
@ -25,6 +26,9 @@ namespace HuanMeng.DotNetCore.Redis
|
|||
/// </summary>
|
||||
public static ConcurrentDictionary<string, IDatabase> Redis { get; set; } = new ConcurrentDictionary<string, IDatabase>();
|
||||
|
||||
/// <summary>
|
||||
/// 数据库查询
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<string, IServer> RedisServer { get; set; } = new ConcurrentDictionary<string, IServer>();
|
||||
|
||||
|
||||
|
|
@ -55,13 +59,62 @@ namespace HuanMeng.DotNetCore.Redis
|
|||
if (!RedisServer.TryGetValue(redisConnection, out var server))
|
||||
{
|
||||
var redis = ConnectionMultiplexer.Connect(redisConnection);
|
||||
server = redis.GetServer("", "");
|
||||
var serverConn = ParseIpPortAndDatabase(redisConnection);
|
||||
server = redis.GetServer(serverConn.ip, serverConn.port);
|
||||
//server.key
|
||||
//redis.GetServer()
|
||||
RedisServer.TryAdd(redisConnection, server);
|
||||
}
|
||||
return server;
|
||||
}
|
||||
private static (string ip, int port, int database) ParseIpPortAndDatabase(string connectionString)
|
||||
{
|
||||
// 默认端口号和默认数据库
|
||||
int defaultPort = 6379;
|
||||
int defaultDatabase = 0;
|
||||
|
||||
if (string.IsNullOrEmpty(connectionString))
|
||||
{
|
||||
return ("localhost", defaultPort, defaultDatabase);
|
||||
}
|
||||
|
||||
// 按逗号分割,获取主机部分和其他参数
|
||||
var parts = connectionString.Split(',');
|
||||
var hostPart = parts[0]; // 例如:"192.168.195.6:6379"
|
||||
|
||||
// 检查是否包含端口号
|
||||
string ip;
|
||||
int port;
|
||||
|
||||
if (hostPart.Contains(":"))
|
||||
{
|
||||
var hostParts = hostPart.Split(':');
|
||||
ip = hostParts[0];
|
||||
port = int.TryParse(hostParts[1], out int parsedPort) ? parsedPort : defaultPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果没有端口号,使用默认端口
|
||||
ip = hostPart;
|
||||
port = defaultPort;
|
||||
}
|
||||
|
||||
// 解析 defaultDatabase 参数
|
||||
int database = defaultDatabase;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (part.StartsWith("defaultDatabase=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var dbPart = part.Split('=');
|
||||
if (dbPart.Length == 2 && int.TryParse(dbPart[1], out int parsedDb))
|
||||
{
|
||||
database = parsedDb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (ip, port, database);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
@ -141,7 +194,26 @@ namespace HuanMeng.DotNetCore.Redis
|
|||
/// <returns></returns>
|
||||
public static List<string> ScanKeys(this IServer server, string pattern, int pageSize = 100)
|
||||
{
|
||||
var matchingKeys = server.Keys(pattern: pattern).Select(it => it.ToString()).ToList();
|
||||
var matchingKeys = server.Keys(pattern: pattern, pageSize: pageSize).Select(it => it.ToString()).ToList();
|
||||
return matchingKeys;
|
||||
}
|
||||
/// <summary>
|
||||
/// 异步模糊查询key
|
||||
/// </summary>
|
||||
/// <param name="server"></param>
|
||||
/// <param name="pattern"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="database"></param>
|
||||
/// <returns>匹配的键的字符串列表</returns>
|
||||
public static async Task<List<string>> ScanKeysAsync(this IServer server, string pattern, int pageSize = 100, int database = -1)
|
||||
{
|
||||
var matchingKeys = new List<string>();
|
||||
|
||||
await foreach (var key in server.KeysAsync(database: database, pattern: pattern, pageSize: pageSize))
|
||||
{
|
||||
matchingKeys.Add(key.ToString());
|
||||
}
|
||||
|
||||
return matchingKeys;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,5 +35,30 @@ namespace HuanMeng.DotNetCore.Utility
|
|||
// 如果X-Forwarded-For头部不存在,使用RemoteIpAddress
|
||||
return context.Connection.RemoteIpAddress?.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从请求头中提取Authorization信息(JWT)。
|
||||
/// </summary>
|
||||
/// <param name="headers">请求头字典。</param>
|
||||
/// <returns>如果包含有效的Authorization头,则返回JWT Token,否则返回null。</returns>
|
||||
public static string? GetAuthorization(this IHeaderDictionary headers)
|
||||
{
|
||||
// 尝试从请求头中获取Authorization字段
|
||||
if (headers.TryGetValue("Authorization", out var authHeaderObj))
|
||||
{
|
||||
// 获取Authorization头的值并移除"Bearer "前缀
|
||||
var authHeader = authHeaderObj.ToString();
|
||||
|
||||
// 如果Authorization以"Bearer "开头,提取JWT Token
|
||||
if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return authHeader.Substring(7).Trim(); // 直接返回JWT Token
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有Authorization头或格式不正确,返回null
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user