增加数据库管理

This commit is contained in:
LemonNoCry 2023-04-14 10:43:47 +08:00
parent 8183be9d58
commit e9f1ef5c01
No known key found for this signature in database
16 changed files with 789 additions and 377 deletions

View File

@ -106,6 +106,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\Systems\" />
<Folder Include="wwwroot\BlogCore.Data.excel\" />
</ItemGroup>

View File

@ -1957,6 +1957,11 @@
找不到指定资源
</summary>
</member>
<member name="T:Blog.Core.Model.Systems.DataBase.DataBaseReadType">
<summary>
数据库读取类型
</summary>
</member>
<member name="T:Blog.Core.Model.TableModel`1">
<summary>
表格数据,支持分页

View File

@ -1299,6 +1299,46 @@
<param name="id"></param>
<returns></returns>
</member>
<member name="T:Blog.Core.Api.Controllers.Systems.DataBaseController">
<summary>
数据库管理
</summary>
</member>
<member name="M:Blog.Core.Api.Controllers.Systems.DataBaseController.GetAllConfig">
<summary>
获取库配置
</summary>
<returns></returns>
</member>
<member name="M:Blog.Core.Api.Controllers.Systems.DataBaseController.GetTableInfoList(System.String,Blog.Core.Model.Systems.DataBase.DataBaseReadType)">
<summary>
获取表信息
</summary>
<param name="configId">配置Id</param>
<param name="readType">读取类型</param>
<returns></returns>
</member>
<member name="M:Blog.Core.Api.Controllers.Systems.DataBaseController.GetColumnInfosByTableName(System.String,System.String,Blog.Core.Model.Systems.DataBase.DataBaseReadType)">
<summary>
获取表字段
</summary>
<param name="tableName">表名</param>
<param name="configId">ConfigId</param>
<param name="readType">读取类型</param>
<returns></returns>
</member>
<member name="M:Blog.Core.Api.Controllers.Systems.DataBaseController.PutTableEditRemark(Blog.Core.Model.Systems.DataBase.EditTableInput)">
<summary>
编辑表备注
</summary>
<param name="input"></param>
</member>
<member name="M:Blog.Core.Api.Controllers.Systems.DataBaseController.PutColumnEditRemark(Blog.Core.Model.Systems.DataBase.EditColumnInput)">
<summary>
编辑列备注
</summary>
<param name="input"></param>
</member>
<member name="T:Blog.Core.Api.Controllers.Tenant.TenantByDbController">
<summary>
多租户-多库方案 测试

View File

@ -4,82 +4,85 @@ using System.Collections.Generic;
namespace Blog.Core.Controllers
{
public class BaseApiController : Controller
{
[NonAction]
public MessageModel<T> Success<T>(T data, string msg = "成功")
{
return new MessageModel<T>()
{
success = true,
msg = msg,
response = data,
};
}
// [NonAction]
//public MessageModel<T> Success<T>(T data, string msg = "成功",bool success = true)
//{
// return new MessageModel<T>()
// {
// success = success,
// msg = msg,
// response = data,
// };
//}
[NonAction]
public MessageModel Success(string msg = "成功")
{
return new MessageModel()
{
success = true,
msg = msg,
response = null,
};
}
[NonAction]
public MessageModel<string> Failed(string msg = "失败", int status = 500)
{
return new MessageModel<string>()
{
success = false,
status = status,
msg = msg,
response = null,
};
}
[NonAction]
public MessageModel<T> Failed<T>(string msg = "失败", int status = 500)
{
return new MessageModel<T>()
{
success = false,
status = status,
msg = msg,
response = default,
};
}
[NonAction]
public MessageModel<PageModel<T>> SuccessPage<T>(int page, int dataCount, int pageSize, List<T> data, int pageCount, string msg = "获取成功")
{
public class BaseApiController : Controller
{
[NonAction]
public MessageModel<T> Success<T>(T data, string msg = "成功")
{
return new MessageModel<T>()
{
success = true,
msg = msg,
response = data,
};
}
return new MessageModel<PageModel<T>>()
{
success = true,
msg = msg,
response = new PageModel<T>(page, dataCount, pageSize, data)
// [NonAction]
//public MessageModel<T> Success<T>(T data, string msg = "成功",bool success = true)
//{
// return new MessageModel<T>()
// {
// success = success,
// msg = msg,
// response = data,
// };
//}
[NonAction]
public MessageModel Success(string msg = "成功")
{
return new MessageModel()
{
success = true,
msg = msg,
response = null,
};
}
[NonAction]
public MessageModel<string> Failed(string msg = "失败", int status = 500)
{
return new MessageModel<string>()
{
success = false,
status = status,
msg = msg,
response = null,
};
}
};
}
[NonAction]
public MessageModel<PageModel<T>> SuccessPage<T>(PageModel<T> pageModel, string msg = "获取成功")
{
[NonAction]
public MessageModel<T> Failed<T>(string msg = "失败", int status = 500)
{
return new MessageModel<T>()
{
success = false,
status = status,
msg = msg,
response = default,
};
}
return new MessageModel<PageModel<T>>()
{
success = true,
msg = msg,
response = pageModel
};
}
}
}
[NonAction]
public MessageModel<PageModel<T>> SuccessPage<T>(int page, int dataCount, int pageSize, List<T> data,
int pageCount, string msg = "获取成功")
{
return new MessageModel<PageModel<T>>()
{
success = true,
msg = msg,
response = new PageModel<T>(page, dataCount, pageSize, data)
};
}
[NonAction]
public MessageModel<PageModel<T>> SuccessPage<T>(PageModel<T> pageModel, string msg = "获取成功")
{
return new MessageModel<PageModel<T>>()
{
success = true,
msg = msg,
response = pageModel
};
}
}
}

View File

@ -0,0 +1,188 @@
using System.Diagnostics.CodeAnalysis;
using Blog.Core.Common;
using Blog.Core.Common.DB;
using Blog.Core.Controllers;
using Blog.Core.Model;
using Blog.Core.Model.Models;
using Blog.Core.Model.Systems.DataBase;
using Blog.Core.Model.Tenants;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
namespace Blog.Core.Api.Controllers.Systems;
/// <summary>
/// 数据库管理
/// </summary>
[Route("api/Systems/[controller]/[action]")]
[ApiController]
[Authorize(Permissions.Name)]
public class DataBaseController : BaseApiController
{
private readonly ISqlSugarClient _db;
public DataBaseController(ISqlSugarClient db)
{
_db = db;
}
[return: NotNull]
public ISqlSugarClient GetTenantDb(string configId)
{
if (!_db.AsTenant().IsAnyConnection(configId))
{
var tenant = _db.Queryable<SysTenant>().WithCache()
.Where(s => s.TenantType == TenantTypeEnum.Db)
.Where(s => s.ConfigId == configId)
.First();
if (tenant != null)
{
_db.AsTenant().AddConnection(tenant.GetConnectionConfig());
}
}
var db = _db.AsTenant().GetConnectionScope(configId);
if (db is null)
{
throw new ApplicationException("无效的数据库配置");
}
return db;
}
/// <summary>
/// 获取库配置
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<MessageModel<List<DatabaseOutput>>> GetAllConfig()
{
//增加多租户的连接
var allConfigs = new List<ConnectionConfig>(BaseDBConfig.AllConfigs);
var tenants = await _db.Queryable<SysTenant>().WithCache()
.Where(s => s.TenantType == TenantTypeEnum.Db)
.ToListAsync();
if (tenants.Any())
{
allConfigs.AddRange(tenants.Select(tenant => tenant.GetConnectionConfig()));
}
var configs = await Task.FromResult(allConfigs);
return Success(configs.Adapt<List<DatabaseOutput>>());
}
/// <summary>
/// 获取表信息
/// </summary>
/// <param name="configId">配置Id</param>
/// <param name="readType">读取类型</param>
/// <returns></returns>
[HttpGet]
public MessageModel<List<DbTableInfo>> GetTableInfoList(string configId,
DataBaseReadType readType = DataBaseReadType.Db)
{
if (configId.IsNullOrEmpty())
{
configId = MainDb.CurrentDbConnId;
}
var provider = GetTenantDb(configId);
List<DbTableInfo> data = null;
switch (readType)
{
case DataBaseReadType.Db:
data = provider.DbMaintenance.GetTableInfoList(false);
break;
case DataBaseReadType.Entity:
if (EntityUtility.TenantEntitys.TryGetValue(configId, out var types))
{
data = types.Select(s => provider.EntityMaintenance.GetEntityInfo(s))
.Select(s => new {Name = s.DbTableName, Description = s.TableDescription})
.Adapt<List<DbTableInfo>>();
}
break;
}
return Success(data);
}
/// <summary>
/// 获取表字段
/// </summary>
/// <param name="tableName">表名</param>
/// <param name="configId">ConfigId</param>
/// <param name="readType">读取类型</param>
/// <returns></returns>
[HttpGet]
public MessageModel<List<DbColumnInfoOutput>> GetColumnInfosByTableName(string tableName, string configId = null,
DataBaseReadType readType = DataBaseReadType.Db)
{
if (string.IsNullOrWhiteSpace(tableName))
return Failed<List<DbColumnInfoOutput>>("表名不能为空");
if (configId.IsNullOrEmpty())
{
configId = MainDb.CurrentDbConnId;
}
List<DbColumnInfoOutput> data = null;
var provider = GetTenantDb(configId);
switch (readType)
{
case DataBaseReadType.Db:
data = provider.DbMaintenance.GetColumnInfosByTableName(tableName, false)
.Adapt<List<DbColumnInfoOutput>>();
break;
case DataBaseReadType.Entity:
if (EntityUtility.TenantEntitys.TryGetValue(configId, out var types))
{
var type = types.FirstOrDefault(s => s.Name == tableName);
data = provider.EntityMaintenance.GetEntityInfo(type).Columns.Adapt<List<DbColumnInfoOutput>>();
}
break;
}
return Success(data);
}
/// <summary>
/// 编辑表备注
/// </summary>
/// <param name="input"></param>
[HttpPut]
public MessageModel PutTableEditRemark([FromBody] EditTableInput input)
{
var provider = GetTenantDb(input.ConfigId);
if (provider.DbMaintenance.IsAnyTableRemark(input.TableName))
{
provider.DbMaintenance.DeleteTableRemark(input.TableName);
}
provider.DbMaintenance.AddTableRemark(input.TableName, input.Description);
return Success();
}
/// <summary>
/// 编辑列备注
/// </summary>
/// <param name="input"></param>
[HttpPut]
public MessageModel PutColumnEditRemark([FromBody] EditColumnInput input)
{
var provider = GetTenantDb(input.ConfigId);
if (provider.DbMaintenance.IsAnyColumnRemark(input.DbColumnName, input.TableName))
{
provider.DbMaintenance.DeleteColumnRemark(input.DbColumnName, input.TableName);
}
provider.DbMaintenance.AddColumnRemark(input.DbColumnName, input.TableName, input.ColumnDescription);
return Success();
}
}

View File

@ -18,6 +18,9 @@
<ItemGroup>
<PackageReference Include="Magicodes.IE.Excel" Version="2.6.4" />
<PackageReference Include="InitQ" Version="1.0.0.12" />
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Mapster" Version="7.3.0" />
<PackageReference Include="Mapster.Core" Version="1.2.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />

View File

@ -3,18 +3,23 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SqlSugar;
namespace Blog.Core.Common.DB
{
public class BaseDBConfig
{
public static readonly List<ConnectionConfig> AllConfigs = new(); //所有库配置
public static readonly List<SlaveConnectionConfig> AllSlaveConfigs = new(); //从库配置
public static List<ConnectionConfig> ValidConfig = new(); //有效的库连接(除去Log库)
public static ConnectionConfig LogConfig; //日志库
/* GitHub的历史记录
* appsettings.json设置为true的第一个db连接
*/
public static (List<MutiDBOperate> allDbs, List<MutiDBOperate> slaveDbs) MutiConnectionString => MutiInitConn();
public static List<ConnectionConfig> AllConfig = new(); //所有的库连接
public static List<ConnectionConfig> ValidConfig = new(); //有效的库连接(除去Log库)
public static ConnectionConfig LogConfig; //日志库
private static string DifDBConnOfSecurity(params string[] conn)
{
@ -54,7 +59,7 @@ namespace Blog.Core.Common.DB
List<MutiDBOperate> listdatabaseSlaveDB = new List<MutiDBOperate>(); //从库
// 单库,且不开启读写分离,只保留一个
if (!AppSettings.app(new string[] { "CQRSEnabled" }).ObjToBool() && !AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool())
if (!AppSettings.app(new string[] {"CQRSEnabled"}).ObjToBool() && !AppSettings.app(new string[] {"MutiDBEnabled"}).ObjToBool())
{
if (listdatabase.Count == 1)
{
@ -62,7 +67,7 @@ namespace Blog.Core.Common.DB
}
else
{
var dbFirst = listdatabase.FirstOrDefault(d => d.ConnId == AppSettings.app(new string[] { "MainDB" }).ObjToString());
var dbFirst = listdatabase.FirstOrDefault(d => d.ConnId == AppSettings.app(new string[] {"MainDB"}).ObjToString());
if (dbFirst == null)
{
dbFirst = listdatabase.FirstOrDefault();
@ -75,11 +80,11 @@ namespace Blog.Core.Common.DB
// 读写分离,且必须是单库模式,获取从库
if (AppSettings.app(new string[] { "CQRSEnabled" }).ObjToBool() && !AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool())
if (AppSettings.app(new string[] {"CQRSEnabled"}).ObjToBool() && !AppSettings.app(new string[] {"MutiDBEnabled"}).ObjToBool())
{
if (listdatabase.Count > 1)
{
listdatabaseSlaveDB = listdatabase.Where(d => d.ConnId != AppSettings.app(new string[] { "MainDB" }).ObjToString()).ToList();
listdatabaseSlaveDB = listdatabase.Where(d => d.ConnId != AppSettings.app(new string[] {"MainDB"}).ObjToString()).ToList();
}
}

View File

@ -0,0 +1,53 @@
using Blog.Core.Common.Extensions;
using Blog.Core.Model;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
namespace Blog.Core.Common.DB;
public class EntityUtility
{
private static readonly Lazy<Dictionary<string, List<Type>>> _tenantEntitys = new(() =>
{
Dictionary<string, List<Type>> dic = new Dictionary<string, List<Type>>();
var assembly = Assembly.Load("Blog.Core.Model");
//扫描 实体
foreach (var type in assembly.GetTypes().Where(s => s.IsClass && !s.IsAbstract))
{
var tenant = type.GetCustomAttribute<TenantAttribute>();
if (tenant != null)
{
dic.TryAdd(tenant.configId.ToString(), type);
continue;
}
if (type.IsSubclassOf(typeof(RootEntityTkey<>)))
{
dic.TryAdd(MainDb.CurrentDbConnId, type);
continue;
}
var table = type.GetCustomAttribute<SugarTable>();
if (table != null)
{
dic.TryAdd(MainDb.CurrentDbConnId, type);
continue;
}
Debug.Assert(type.Namespace != null, "type.Namespace != null");
if (type.Namespace.StartsWith("Blog.Core.Model.Models"))
{
dic.TryAdd(MainDb.CurrentDbConnId, type);
continue;
}
}
return dic;
});
public static Dictionary<string, List<Type>> TenantEntitys => _tenantEntitys.Value;
}

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Blog.Core.Common.Extensions;
public static class DictionaryExtensions
{
public static void TryAdd<TKey, TValue>(this IDictionary<TKey, List<TValue>> dic, TKey key, TValue value)
{
if (dic.TryGetValue(key, out var old))
{
old.Add(value);
}
else
{
dic.Add(key, new List<TValue> {value});
}
}
}

View File

@ -14,212 +14,229 @@ using System.Linq;
using System.Security.Claims;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Blog.Core.Model.Models;
namespace Blog.Core.AuthHelper
{
/// <summary>
/// 权限授权处理器
/// </summary>
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
/// <summary>
/// 验证方案提供对象
/// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; }
/// <summary>
/// 权限授权处理器
/// </summary>
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
/// <summary>
/// 验证方案提供对象
/// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; }
private readonly IRoleModulePermissionServices _roleModulePermissionServices;
private readonly IHttpContextAccessor _accessor;
private readonly ISysUserInfoServices _userServices;
private readonly IUser _user;
private readonly IRoleModulePermissionServices _roleModulePermissionServices;
private readonly IHttpContextAccessor _accessor;
private readonly ISysUserInfoServices _userServices;
private readonly IUser _user;
/// <summary>
/// 构造函数注入
/// </summary>
/// <param name="schemes"></param>
/// <param name="roleModulePermissionServices"></param>
/// <param name="accessor"></param>
/// <param name="userServices"></param>
/// <param name="user"></param>
public PermissionHandler(IAuthenticationSchemeProvider schemes, IRoleModulePermissionServices roleModulePermissionServices, IHttpContextAccessor accessor, ISysUserInfoServices userServices, IUser user)
{
_accessor = accessor;
_userServices = userServices;
_user = user;
Schemes = schemes;
_roleModulePermissionServices = roleModulePermissionServices;
}
/// <summary>
/// 构造函数注入
/// </summary>
/// <param name="schemes"></param>
/// <param name="roleModulePermissionServices"></param>
/// <param name="accessor"></param>
/// <param name="userServices"></param>
/// <param name="user"></param>
public PermissionHandler(IAuthenticationSchemeProvider schemes,
IRoleModulePermissionServices roleModulePermissionServices, IHttpContextAccessor accessor,
ISysUserInfoServices userServices, IUser user)
{
_accessor = accessor;
_userServices = userServices;
_user = user;
Schemes = schemes;
_roleModulePermissionServices = roleModulePermissionServices;
}
// 重写异步处理程序
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
var httpContext = _accessor.HttpContext;
// 重写异步处理程序
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
PermissionRequirement requirement)
{
var httpContext = _accessor.HttpContext;
// 获取系统中所有的角色和菜单的关系集合
if (!requirement.Permissions.Any())
{
var data = await _roleModulePermissionServices.RoleModuleMaps();
var list = new List<PermissionItem>();
// ids4和jwt切换
// ids4
if (Permissions.IsUseIds4)
{
list = (from item in data
where item.IsDeleted == false
orderby item.Id
select new PermissionItem
{
Url = item.Module?.LinkUrl,
Role = item.Role?.Id.ObjToString(),
}).ToList();
}
// jwt
else
{
list = (from item in data
where item.IsDeleted == false
orderby item.Id
select new PermissionItem
{
Url = item.Module?.LinkUrl,
Role = item.Role?.Name.ObjToString(),
}).ToList();
}
// 获取系统中所有的角色和菜单的关系集合
if (!requirement.Permissions.Any())
{
var data = await _roleModulePermissionServices.RoleModuleMaps();
var list = new List<PermissionItem>();
// ids4和jwt切换
// ids4
if (Permissions.IsUseIds4)
{
list = (from item in data
where item.IsDeleted == false
orderby item.Id
select new PermissionItem
{
Url = item.Module?.LinkUrl,
Role = item.Role?.Id.ObjToString(),
}).ToList();
}
// jwt
else
{
list = (from item in data
where item.IsDeleted == false
orderby item.Id
select new PermissionItem
{
Url = item.Module?.LinkUrl,
Role = item.Role?.Name.ObjToString(),
}).ToList();
}
requirement.Permissions = list;
}
requirement.Permissions = list;
}
if (httpContext != null)
{
var questUrl = httpContext.Request.Path.Value.ToLower();
if (httpContext != null)
{
var questUrl = httpContext.Request.Path.Value.ToLower();
// 整体结构类似认证中间件UseAuthentication的逻辑具体查看开源地址
// https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/Core/src/AuthenticationMiddleware.cs
httpContext.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
{
OriginalPath = httpContext.Request.Path,
OriginalPathBase = httpContext.Request.PathBase
});
// 整体结构类似认证中间件UseAuthentication的逻辑具体查看开源地址
// https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/Core/src/AuthenticationMiddleware.cs
httpContext.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
{
OriginalPath = httpContext.Request.Path,
OriginalPathBase = httpContext.Request.PathBase
});
// Give any IAuthenticationRequestHandler schemes a chance to handle the request
// 主要作用是: 判断当前是否需要进行远程验证,如果是就进行远程验证
var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
{
if (await handlers.GetHandlerAsync(httpContext, scheme.Name) is IAuthenticationRequestHandler handler && await handler.HandleRequestAsync())
{
context.Fail();
return;
}
}
// Give any IAuthenticationRequestHandler schemes a chance to handle the request
// 主要作用是: 判断当前是否需要进行远程验证,如果是就进行远程验证
var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
{
if (await handlers.GetHandlerAsync(httpContext, scheme.Name) is IAuthenticationRequestHandler
handler && await handler.HandleRequestAsync())
{
context.Fail();
return;
}
}
//判断请求是否拥有凭据,即有没有登录
var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
if (defaultAuthenticate != null)
{
var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
// 是否开启测试环境
var isTestCurrent = AppSettings.app(new string[] {"AppSettings", "UseLoadTest"}).ObjToBool();
//判断请求是否拥有凭据,即有没有登录
var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
if (defaultAuthenticate != null)
{
var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
//result?.Principal不为空即登录成功
if (result?.Principal != null || isTestCurrent)
{
if (!isTestCurrent) httpContext.User = result.Principal;
// 是否开启测试环境
var isTestCurrent = AppSettings.app(new string[] { "AppSettings", "UseLoadTest" }).ObjToBool();
// 获取当前用户的角色信息
var currentUserRoles = new List<string>();
// ids4和jwt切换
// ids4
if (Permissions.IsUseIds4)
{
currentUserRoles = (from item in httpContext.User.Claims
where item.Type == "role"
select item.Value).ToList();
}
else
{
// jwt
currentUserRoles = (from item in httpContext.User.Claims
where item.Type == requirement.ClaimType
select item.Value).ToList();
}
//result?.Principal不为空即登录成功
if (result?.Principal != null || isTestCurrent)
{
if (!isTestCurrent) httpContext.User = result.Principal;
//超级管理员 默认拥有所有权限
if (currentUserRoles.All(s => s != "SuperAdmin"))
{
var isMatchRole = false;
var permisssionRoles = requirement.Permissions.Where(w => currentUserRoles.Contains(w.Role));
foreach (var item in permisssionRoles)
{
try
{
if (Regex.Match(questUrl, item.Url?.ObjToString().ToLower())?.Value == questUrl)
{
isMatchRole = true;
break;
}
}
catch (Exception)
{
// ignored
}
}
// 获取当前用户的角色信息
var currentUserRoles = new List<string>();
// ids4和jwt切换
// ids4
if (Permissions.IsUseIds4)
{
currentUserRoles = (from item in httpContext.User.Claims
where item.Type == "role"
select item.Value).ToList();
}
else
{
// jwt
currentUserRoles = (from item in httpContext.User.Claims
where item.Type == requirement.ClaimType
select item.Value).ToList();
}
//验证权限
if (currentUserRoles.Count <= 0 || !isMatchRole)
{
context.Fail();
return;
}
}
// 判断token是否过期过期则重新登录
var isExp = false;
// ids4和jwt切换
// ids4
if (Permissions.IsUseIds4)
{
isExp = (httpContext.User.Claims.SingleOrDefault(s => s.Type == "exp")?.Value) != null &&
DateHelper.StampToDateTime(httpContext.User.Claims
.SingleOrDefault(s => s.Type == "exp")?.Value) >= DateTime.Now;
}
else
{
// jwt
isExp =
(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)
?.Value) != null &&
DateTime.Parse(httpContext.User.Claims
.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) >= DateTime.Now;
}
var isMatchRole = false;
var permisssionRoles = requirement.Permissions.Where(w => currentUserRoles.Contains(w.Role));
foreach (var item in permisssionRoles)
{
try
{
if (Regex.Match(questUrl, item.Url?.ObjToString().ToLower())?.Value == questUrl)
{
isMatchRole = true;
break;
}
}
catch (Exception)
{
// ignored
}
}
if (!isExp)
{
context.Fail(new AuthorizationFailureReason(this, "授权已过期,请重新授权"));
return;
}
//验证权限
if (currentUserRoles.Count <= 0 || !isMatchRole)
{
context.Fail();
return;
}
//校验签发时间
if (!Permissions.IsUseIds4)
{
var value = httpContext.User.Claims
.SingleOrDefault(s => s.Type == JwtRegisteredClaimNames.Iat)?.Value;
if (value != null)
{
var user = await _userServices.QueryById(_user.ID, true);
if (user.CriticalModifyTime > value.ObjToDate())
{
_user.MessageModel = new ApiResponse(StatusCode.CODE401, "很抱歉,授权已失效,请重新授权")
.MessageModel;
context.Fail(new AuthorizationFailureReason(this, _user.MessageModel.msg));
return;
}
}
}
// 判断token是否过期过期则重新登录
var isExp = false;
// ids4和jwt切换
// ids4
if (Permissions.IsUseIds4)
{
isExp = (httpContext.User.Claims.SingleOrDefault(s => s.Type == "exp")?.Value) != null && DateHelper.StampToDateTime(httpContext.User.Claims.SingleOrDefault(s => s.Type == "exp")?.Value) >= DateTime.Now;
}
else
{
// jwt
isExp = (httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) != null && DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) >= DateTime.Now;
}
context.Succeed(requirement);
return;
}
}
if (!isExp)
{
context.Fail(new AuthorizationFailureReason(this, "授权已过期,请重新授权"));
return;
}
//判断没有登录时是否访问登录的url,并且是Post请求并且是form表单提交类型否则为失败
if (!(questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) &&
(!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasFormContentType)))
{
context.Fail();
return;
}
}
//校验签发时间
if (!Permissions.IsUseIds4)
{
var value = httpContext.User.Claims.SingleOrDefault(s => s.Type == JwtRegisteredClaimNames.Iat)?.Value;
if (value != null)
{
var user = await _userServices.QueryById(_user.ID, true);
if (user.CriticalModifyTime > value.ObjToDate())
{
_user.MessageModel = new ApiResponse(StatusCode.CODE401, "很抱歉,授权已失效,请重新授权").MessageModel;
context.Fail(new AuthorizationFailureReason(this, _user.MessageModel.msg));
return;
}
}
}
context.Succeed(requirement);
return;
}
}
//判断没有登录时是否访问登录的url,并且是Post请求并且是form表单提交类型否则为失败
if (!(questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasFormContentType)))
{
context.Fail();
return;
}
}
//context.Succeed(requirement);
}
}
//context.Succeed(requirement);
}
}
}

View File

@ -13,126 +13,130 @@ using System.Threading.Tasks;
namespace Blog.Core.Extensions
{
/// <summary>
/// SqlSugar 启动服务
/// </summary>
public static class SqlsugarSetup
{
private static readonly MemoryCache Cache = new MemoryCache(new MemoryCacheOptions());
/// <summary>
/// SqlSugar 启动服务
/// </summary>
public static class SqlsugarSetup
{
private static readonly MemoryCache Cache = new MemoryCache(new MemoryCacheOptions());
public static void AddSqlsugarSetup(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
public static void AddSqlsugarSetup(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
// 默认添加主数据库连接
MainDb.CurrentDbConnId = AppSettings.app(new string[] { "MainDB" });
// 默认添加主数据库连接
MainDb.CurrentDbConnId = AppSettings.app(new string[] {"MainDB"});
// SqlSugarScope是线程安全可使用单例注入
// 参考https://www.donet5.com/Home/Doc?typeId=1181
services.AddSingleton<ISqlSugarClient>(o =>
{
var memoryCache = o.GetRequiredService<IMemoryCache>();
BaseDBConfig.MutiConnectionString.slaveDbs.ForEach(s =>
{
BaseDBConfig.AllSlaveConfigs.Add(new SlaveConnectionConfig()
{
HitRate = s.HitRate,
ConnectionString = s.Connection
});
});
// 从库
var listConfig_Slave = new List<SlaveConnectionConfig>();
BaseDBConfig.MutiConnectionString.slaveDbs.ForEach(s =>
{
listConfig_Slave.Add(new SlaveConnectionConfig()
{
HitRate = s.HitRate,
ConnectionString = s.Connection
});
});
BaseDBConfig.MutiConnectionString.allDbs.ForEach(m =>
{
var config = new ConnectionConfig()
{
ConfigId = m.ConnId.ObjToString().ToLower(),
ConnectionString = m.Connection,
DbType = (DbType) m.DbType,
IsAutoCloseConnection = true,
// Check out more information: https://github.com/anjoy8/Blog.Core/issues/122
//IsShardSameThread = false,
MoreSettings = new ConnMoreSettings()
{
//IsWithNoLockQuery = true,
IsAutoRemoveDataCache = true,
SqlServerCodeFirstNvarchar = true,
},
// 从库
SlaveConnectionConfigs = BaseDBConfig.AllSlaveConfigs,
// 自定义特性
ConfigureExternalServices = new ConfigureExternalServices()
{
EntityService = (property, column) =>
{
if (column.IsPrimarykey && property.PropertyType == typeof(int))
{
column.IsIdentity = true;
}
}
},
InitKeyType = InitKeyType.Attribute
};
if (SqlSugarConst.LogConfigId.ToLower().Equals(m.ConnId.ToLower()))
{
BaseDBConfig.LogConfig = config;
}
else
{
BaseDBConfig.ValidConfig.Add(config);
}
BaseDBConfig.MutiConnectionString.allDbs.ForEach(m =>
{
var config = new ConnectionConfig()
{
ConfigId = m.ConnId.ObjToString().ToLower(),
ConnectionString = m.Connection,
DbType = (DbType)m.DbType,
IsAutoCloseConnection = true,
// Check out more information: https://github.com/anjoy8/Blog.Core/issues/122
//IsShardSameThread = false,
MoreSettings = new ConnMoreSettings()
{
//IsWithNoLockQuery = true,
IsAutoRemoveDataCache = true,
SqlServerCodeFirstNvarchar = true,
},
// 从库
SlaveConnectionConfigs = listConfig_Slave,
// 自定义特性
ConfigureExternalServices = new ConfigureExternalServices()
{
DataInfoCacheService = new SqlSugarMemoryCacheService(memoryCache),
EntityService = (property, column) =>
{
if (column.IsPrimarykey && property.PropertyType == typeof(int))
{
column.IsIdentity = true;
}
}
},
InitKeyType = InitKeyType.Attribute
};
if (SqlSugarConst.LogConfigId.ToLower().Equals(m.ConnId.ToLower()))
{
BaseDBConfig.LogConfig = config;
}
else
{
BaseDBConfig.ValidConfig.Add(config);
}
BaseDBConfig.AllConfigs.Add(config);
});
BaseDBConfig.AllConfig.Add(config);
});
if (BaseDBConfig.LogConfig is null)
{
throw new ApplicationException("未配置Log库连接");
}
if (BaseDBConfig.LogConfig is null)
{
throw new ApplicationException("未配置Log库连接");
}
return new SqlSugarScope(BaseDBConfig.AllConfig, db =>
{
BaseDBConfig.ValidConfig.ForEach(config =>
{
var dbProvider = db.GetConnectionScope((string)config.ConfigId);
// SqlSugarScope是线程安全可使用单例注入
// 参考https://www.donet5.com/Home/Doc?typeId=1181
services.AddSingleton<ISqlSugarClient>(o =>
{
var memoryCache = o.GetRequiredService<IMemoryCache>();
// 打印SQL语句
dbProvider.Aop.OnLogExecuting = (s, parameters) => SqlSugarAop.OnLogExecuting(dbProvider, s, parameters, config);
foreach (var config in BaseDBConfig.AllConfigs)
{
config.ConfigureExternalServices.DataInfoCacheService = new SqlSugarMemoryCacheService(memoryCache);
}
// 数据审计
dbProvider.Aop.DataExecuting = SqlSugarAop.DataExecuting;
return new SqlSugarScope(BaseDBConfig.AllConfigs, db =>
{
BaseDBConfig.ValidConfig.ForEach(config =>
{
var dbProvider = db.GetConnectionScope((string) config.ConfigId);
// 配置实体假删除过滤器
RepositorySetting.SetDeletedEntityFilter(dbProvider);
// 配置实体数据权限
RepositorySetting.SetTenantEntityFilter(dbProvider);
});
});
});
}
// 打印SQL语句
dbProvider.Aop.OnLogExecuting = (s, parameters) =>
SqlSugarAop.OnLogExecuting(dbProvider, s, parameters, config);
private static string GetWholeSql(SugarParameter[] paramArr, string sql)
{
foreach (var param in paramArr)
{
sql.Replace(param.ParameterName, param.Value.ObjToString());
}
// 数据审计
dbProvider.Aop.DataExecuting = SqlSugarAop.DataExecuting;
return sql;
}
// 配置实体假删除过滤器
RepositorySetting.SetDeletedEntityFilter(dbProvider);
// 配置实体数据权限
RepositorySetting.SetTenantEntityFilter(dbProvider);
});
});
});
}
private static string GetParas(SugarParameter[] pars)
{
string key = "【SQL参数】";
foreach (var param in pars)
{
key += $"{param.ParameterName}:{param.Value}\n";
}
private static string GetWholeSql(SugarParameter[] paramArr, string sql)
{
foreach (var param in paramArr)
{
sql.Replace(param.ParameterName, param.Value.ObjToString());
}
return key;
}
}
return sql;
}
private static string GetParas(SugarParameter[] pars)
{
string key = "【SQL参数】";
foreach (var param in pars)
{
key += $"{param.ParameterName}:{param.Value}\n";
}
return key;
}
}
}

View File

@ -0,0 +1,10 @@
namespace Blog.Core.Model.Systems.DataBase;
/// <summary>
/// 数据库读取类型
/// </summary>
public enum DataBaseReadType
{
Db,
Entity
}

View File

@ -0,0 +1,10 @@
using SqlSugar;
namespace Blog.Core.Model.Systems.DataBase;
public class DatabaseOutput
{
public string ConfigId { get; set; }
public DbType DbType { get; set; }
}

View File

@ -0,0 +1,36 @@
namespace Blog.Core.Model.Systems.DataBase;
public class DbColumnInfoOutput
{
public string TableName { get; set; }
public int TableId { get; set; }
public string DbColumnName { get; set; }
public string PropertyName { get; set; }
public string DataType { get; set; }
public int Length { get; set; }
public string ColumnDescription { get; set; }
public string DefaultValue { get; set; }
public bool IsNullable { get; set; }
public bool IsIdentity { get; set; }
public bool IsPrimarykey { get; set; }
public object Value { get; set; }
public int DecimalDigits { get; set; }
public int Scale { get; set; }
public bool IsArray { get; set; }
internal bool IsJson { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Blog.Core.Model.Systems.DataBase;
public class EditColumnInput
{
public string ConfigId { get; set; }
public string TableName { get; set; }
public string DbColumnName { get; set; }
public string ColumnDescription { get; set; }
}

View File

@ -0,0 +1,10 @@
namespace Blog.Core.Model.Systems.DataBase;
public class EditTableInput
{
public string ConfigId { get; set; }
public string TableName { get; set; }
public string Description { get; set; }
}