mirror of
https://gitee.com/dotnetchina/OpenAuth.Net.git
synced 2026-07-28 14:17:59 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04142acaaa | ||
|
|
c084e2409f | ||
|
|
4ed8c0819b | ||
|
|
217b407cd9 | ||
|
|
2fb964f9d0 | ||
|
|
6a8eb675e9 | ||
|
|
d7f48e0537 |
237
.cursor/rules/openauth.mdc
Normal file
237
.cursor/rules/openauth.mdc
Normal file
@@ -0,0 +1,237 @@
|
||||
---
|
||||
alwaysApply: false
|
||||
---
|
||||
# OpenAuth.Net Cursor Rules
|
||||
|
||||
## 项目概述
|
||||
OpenAuth.Net是一个基于.NET 9的企业级权限管理和快速开发框架,采用Martin Fowler企业级应用开发思想,集成了最新的技术栈。
|
||||
|
||||
## 技术栈
|
||||
- **后端**: .NET 9, ASP.NET Core WebAPI
|
||||
- **ORM**: SqlSugar (主要) + Entity Framework Core (兼容)
|
||||
- **依赖注入**: Autofac
|
||||
- **数据库**: 支持SqlServer、MySQL、Oracle、PostgreSQL
|
||||
- **定时任务**: Quartz.NET
|
||||
- **缓存**: Redis, MemoryCache
|
||||
- **前端**: Vue2 + Element-UI
|
||||
- **测试**: NUnit
|
||||
- **文档**: Swagger
|
||||
|
||||
## 项目架构
|
||||
```
|
||||
📦OpenAuth.Net
|
||||
┣ 📂Infrastructure # 基础设施层 - 工具类、扩展方法、帮助类
|
||||
┣ 📂OpenAuth.Repository # 数据访问层 - 实体定义、数据访问
|
||||
┣ 📂OpenAuth.App # 应用服务层 - 业务逻辑
|
||||
┣ 📂OpenAuth.WebApi # 表示层 - WebAPI控制器
|
||||
┣ 📂OpenAuth.Identity # 身份认证服务 - IdentityServer4
|
||||
┣ 📂Vue2 # 前端项目
|
||||
┗ 📂数据库脚本 # 数据库初始化脚本
|
||||
```
|
||||
|
||||
## 编码规范
|
||||
|
||||
### 通用规范
|
||||
- 使用C# 9+语法特性
|
||||
- 遵循Microsoft C#编码规范
|
||||
- 类名使用PascalCase,方法名使用PascalCase
|
||||
- 私有字段使用_camelCase,公共属性使用PascalCase
|
||||
- 常量使用UPPER_CASE
|
||||
- 异步方法必须添加Async后缀
|
||||
|
||||
### 命名规范
|
||||
- **Controller**: 以Controller结尾,如`UsersController`
|
||||
- **Service/App**: 以App结尾,如`UserManagerApp`
|
||||
- **Repository**: 以Repository结尾,如`UserRepository`
|
||||
- **Entity**: 实体类直接使用名词,如`SysUser`
|
||||
- **Request**: 请求类以Req结尾,如`QueryUserListReq`
|
||||
- **Response**: 响应类以Resp结尾,如`PagedListDataResp`
|
||||
- **DTO**: 视图模型以View结尾,如`UserView`
|
||||
|
||||
### 注释规范
|
||||
- 所有公共方法必须添加XML注释
|
||||
- 复杂业务逻辑必须添加行内注释
|
||||
- 使用/// <summary>标记方法说明
|
||||
- 参数使用/// <param name="参数名">说明</param>
|
||||
- 返回值使用/// <returns>说明</returns>
|
||||
|
||||
## 分层架构规则
|
||||
|
||||
### Infrastructure层 (基础设施层)
|
||||
- **职责**: 提供通用工具类、扩展方法、帮助类、常量定义
|
||||
- **规则**:
|
||||
- 不依赖其他业务层
|
||||
- 提供可复用的基础功能
|
||||
- 包含缓存、配置、工具类等
|
||||
- **文件组织**:
|
||||
- `/Cache` - 缓存相关
|
||||
- `/Extensions` - 扩展方法
|
||||
- `/Helpers` - 帮助类
|
||||
- `/Const` - 常量定义
|
||||
|
||||
### Repository层 (数据访问层)
|
||||
- **职责**: 数据访问、实体定义、数据库操作
|
||||
- **规则**:
|
||||
- 继承自`BaseRepository<T,TContext>`
|
||||
- 实体类继承自`StringEntity`、`LongEntity`或`IntAutoGenEntity`
|
||||
- 使用SqlSugar或EF Core进行数据访问
|
||||
- 包含DbContext配置
|
||||
- **基类使用**:
|
||||
- `StringEntity`: 字符串主键实体
|
||||
- `LongEntity`: 长整型主键实体
|
||||
- `IntAutoGenEntity`: 自增整型主键实体
|
||||
|
||||
### App层 (应用服务层)
|
||||
- **职责**: 业务逻辑处理、数据传输对象、业务规则
|
||||
- **规则**:
|
||||
- 继承自`SqlSugarBaseApp<T>`、`BaseStringApp<T>`、`BaseLongApp<T>`等基类
|
||||
- 通过构造函数注入依赖
|
||||
- 实现业务逻辑,不直接操作数据库
|
||||
- 使用Request/Response模式
|
||||
- **依赖注入**:
|
||||
```csharp
|
||||
public UserManagerApp(ISqlSugarClient client, RevelanceManagerApp app, IAuth auth)
|
||||
: base(client, auth)
|
||||
```
|
||||
|
||||
### WebApi层 (表示层)
|
||||
- **职责**: HTTP请求处理、参数验证、响应格式化
|
||||
- **规则**:
|
||||
- 继承自`ControllerBase`
|
||||
- 使用`[ApiController]`特性
|
||||
- 统一返回`Response<T>`格式
|
||||
- 进行参数验证
|
||||
- 添加Swagger文档注释
|
||||
|
||||
## 数据库操作规范
|
||||
|
||||
### SqlSugar使用规范
|
||||
```csharp
|
||||
// 查询
|
||||
var users = SugarClient.Queryable<SysUser>()
|
||||
.Where(u => u.Status == 1)
|
||||
.ToList();
|
||||
|
||||
// 分页查询
|
||||
var result = new PagedListDataResp<Role>();
|
||||
var objs = SugarClient.Queryable<Role>();
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
objs = objs.Where(u => u.Name.Contains(request.key));
|
||||
}
|
||||
|
||||
result.Data = await objs.OrderBy(u => u.Name)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit).ToListAsync();
|
||||
result.Count = await objs.CountAsync();
|
||||
return result;
|
||||
|
||||
// 联表查询
|
||||
var result = SugarClient.Queryable<Relevance>()
|
||||
.LeftJoin<SysOrg>((u, o) => u.SecondId == o.Id)
|
||||
.Where((u, o) => u.FirstId == userId && u.RelKey == Define.USERORG)
|
||||
.Select((u, o) => o);
|
||||
return result.ToList();
|
||||
```
|
||||
|
||||
### 事务处理
|
||||
```csharp
|
||||
SugarClient.Ado.BeginTran();
|
||||
try
|
||||
{
|
||||
// 数据库操作
|
||||
SugarClient.Ado.CommitTran();
|
||||
}
|
||||
catch
|
||||
{
|
||||
SugarClient.Ado.RollbackTran();
|
||||
throw;
|
||||
}
|
||||
```
|
||||
|
||||
## 权限和安全规范
|
||||
|
||||
### 权限验证
|
||||
- 使用`IAuth`接口获取当前用户信息
|
||||
- 通过`_auth.GetCurrentUser()`获取登录用户
|
||||
- 数据权限通过机构级联控制
|
||||
|
||||
## API设计规范
|
||||
|
||||
### 控制器设计
|
||||
```csharp
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly UserManagerApp _app;
|
||||
|
||||
public UsersController(UserManagerApp app)
|
||||
{
|
||||
_app = app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户列表
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<Response<PagedListDataResp<UserView>>> Get([FromQuery] QueryUserListReq request)
|
||||
{
|
||||
var result = await _app.Load(request);
|
||||
return Response.Ok(result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖注入规范
|
||||
|
||||
### Autofac配置
|
||||
- 在`AutofacExt.cs`中配置依赖注入
|
||||
- 实现`IDependency`接口的类自动注册
|
||||
- 使用构造函数注入
|
||||
|
||||
## 测试规范
|
||||
|
||||
### 单元测试
|
||||
- 使用NUnit框架
|
||||
- 继承自`TestBase`基类
|
||||
- 测试类以Test结尾
|
||||
- 测试方法使用描述性名称
|
||||
|
||||
### 集成测试
|
||||
- 使用`AutofacWebApplicationFactory`
|
||||
- 模拟HTTP请求
|
||||
- 验证完整的业务流程
|
||||
|
||||
## 工作流规范
|
||||
|
||||
### 流程定义
|
||||
- 使用`FlowScheme`定义流程模板
|
||||
- 通过`FlowInstance`管理流程实例
|
||||
- `FlowNode`表示流程节点
|
||||
|
||||
### 流程引擎
|
||||
- 使用`FlowRuntime`执行流程
|
||||
- 支持顺序、并行、条件等流程类型
|
||||
- 流程状态通过`FlowInstanceStatus`管理
|
||||
|
||||
## 定时任务规范
|
||||
|
||||
### Quartz使用
|
||||
- 继承自`IJob`接口
|
||||
- 在`QuartzService`中注册任务
|
||||
- 支持Cron表达式配置
|
||||
|
||||
## 文档规范
|
||||
|
||||
### 代码文档
|
||||
- 重要业务逻辑添加注释
|
||||
- 复杂算法添加说明
|
||||
- 配置文件添加说明注释
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 配置文件
|
||||
- `appsettings.json`: 基础配置
|
||||
- `appsettings.Development.json`: 开发环境配置
|
||||
- `appsettings.Production.json`: 生产环境配置
|
||||
58
OpenAuth.App/Base/SqlSugarBaseTreeApp.cs
Normal file
58
OpenAuth.App/Base/SqlSugarBaseTreeApp.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.Repository.Core;
|
||||
using SqlSugar;
|
||||
using OpenAuth.Repository.Interface;
|
||||
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
/// <summary>
|
||||
/// 树状结构处理
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// /// <typeparam name="TDbContext"></typeparam>
|
||||
public class SqlSugarBaseTreeApp<T> :SqlSugarBaseApp<T> where T : TreeEntity, new()
|
||||
{
|
||||
|
||||
|
||||
public SqlSugarBaseTreeApp(ISqlSugarClient client, IAuth auth)
|
||||
: base(client, auth)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新树状结构实体
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <typeparam name="U"></typeparam>
|
||||
public void UpdateTreeObj<U>(U obj) where U : TreeEntity, new()
|
||||
{
|
||||
CaculateCascade(obj);
|
||||
|
||||
//获取旧的的CascadeId
|
||||
var cascadeId = SugarClient.Queryable<U>().First(o => o.Id == obj.Id).CascadeId;
|
||||
//根据CascadeId查询子部门
|
||||
var objs = SugarClient.Queryable<U>().Where(u => u.CascadeId.Contains(cascadeId) && u.Id != obj.Id)
|
||||
.OrderBy(u => u.CascadeId).ToList();
|
||||
|
||||
//更新操作
|
||||
SugarClient.Updateable(obj).ExecuteCommand();
|
||||
|
||||
//更新子模块的CascadeId
|
||||
foreach (var a in objs)
|
||||
{
|
||||
a.CascadeId = a.CascadeId.Replace(cascadeId, obj.CascadeId);
|
||||
if (a.ParentId == obj.Id)
|
||||
{
|
||||
a.ParentName = obj.Name;
|
||||
}
|
||||
|
||||
SugarClient.Updateable(a).ExecuteCommand();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,15 @@ using System.Linq;
|
||||
using Infrastructure;
|
||||
using OpenAuth.App.Interface;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using OpenAuth.Repository.Interface;
|
||||
using SqlSugar;
|
||||
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
public class OrgManagerApp : BaseTreeApp<SysOrg,OpenAuthDBContext>
|
||||
public class OrgManagerApp : SqlSugarBaseTreeApp<SysOrg>
|
||||
{
|
||||
private RevelanceManagerApp _revelanceApp;
|
||||
/// <summary>
|
||||
@@ -28,22 +30,20 @@ namespace OpenAuth.App
|
||||
}
|
||||
CaculateCascade(sysOrg);
|
||||
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
{
|
||||
UnitWork.Add(sysOrg);
|
||||
UnitWork.Save();
|
||||
SugarClient.Ado.BeginTran();
|
||||
Repository.Insert(sysOrg);
|
||||
|
||||
//如果当前账号不是SYSTEM,则直接分配
|
||||
if (loginContext.User.Account != Define.SYSTEM_USERNAME)
|
||||
//如果当前账号不是SYSTEM,则直接分配
|
||||
if (loginContext.User.Account != Define.SYSTEM_USERNAME)
|
||||
{
|
||||
_revelanceApp.Assign(new AssignReq
|
||||
{
|
||||
_revelanceApp.Assign(new AssignReq
|
||||
{
|
||||
type = Define.USERORG,
|
||||
firstId = loginContext.User.Id,
|
||||
secIds = new[] { sysOrg.Id }
|
||||
});
|
||||
}
|
||||
});
|
||||
type = Define.USERORG,
|
||||
firstId = loginContext.User.Id,
|
||||
secIds = new[] { sysOrg.Id }
|
||||
});
|
||||
}
|
||||
SugarClient.Ado.CommitTran();
|
||||
|
||||
return sysOrg.Id;
|
||||
}
|
||||
@@ -58,47 +58,48 @@ namespace OpenAuth.App
|
||||
|
||||
return sysOrg.Id;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定ID的部门及其所有子部门
|
||||
/// </summary>
|
||||
public void DelOrgCascade(string[] ids)
|
||||
{
|
||||
var delOrgCascadeIds = UnitWork.Find<SysOrg>(u => ids.Contains(u.Id)).Select(u => u.CascadeId).ToArray();
|
||||
var delOrgCascadeIds = SugarClient.Queryable<SysOrg>().Where(u => ids.Contains(u.Id)).Select(u => u.CascadeId).ToArray();
|
||||
var delOrgIds = new List<string>();
|
||||
foreach (var cascadeId in delOrgCascadeIds)
|
||||
{
|
||||
delOrgIds.AddRange(UnitWork.Find<SysOrg>(u=>u.CascadeId.Contains(cascadeId)).Select(u =>u.Id).ToArray());
|
||||
delOrgIds.AddRange(SugarClient.Queryable<SysOrg>().Where(u => u.CascadeId.Contains(cascadeId)).Select(u => u.Id).ToArray());
|
||||
}
|
||||
|
||||
UnitWork.Delete<Relevance>(u =>u.RelKey == Define.USERORG && delOrgIds.Contains(u.SecondId));
|
||||
UnitWork.Delete<SysOrg>(u => delOrgIds.Contains(u.Id));
|
||||
UnitWork.Save();
|
||||
|
||||
|
||||
SugarClient.Deleteable<Relevance>().Where(u => u.RelKey == Define.USERORG && delOrgIds.Contains(u.SecondId)).ExecuteCommand();
|
||||
SugarClient.Deleteable<SysOrg>().Where(u => delOrgIds.Contains(u.Id)).ExecuteCommand();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载特定用户的部门
|
||||
/// 获取所有机构
|
||||
/// </summary>
|
||||
/// <param name="userId">The user unique identifier.</param>
|
||||
public List<SysOrg> LoadForUser(string userId)
|
||||
/// <returns></returns>
|
||||
public List<OrgView> LoadAll()
|
||||
{
|
||||
var result = from userorg in UnitWork.Find<Relevance>(null)
|
||||
join org in UnitWork.Find<SysOrg>(null) on userorg.SecondId equals org.Id
|
||||
where userorg.FirstId == userId && userorg.RelKey == Define.USERORG
|
||||
select org;
|
||||
return result.ToList();
|
||||
return SugarClient.Queryable<SysOrg>()
|
||||
.LeftJoin<SysUser>((org, user) => org.ChairmanId ==user.Id)
|
||||
.Select((org,user)=>new OrgView
|
||||
{
|
||||
Id = org.Id.SelectAll(),
|
||||
ChairmanName = user.Name
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public OrgManagerApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<SysOrg,OpenAuthDBContext> repository,IAuth auth,
|
||||
RevelanceManagerApp revelanceApp) : base(unitWork, repository, auth)
|
||||
public OrgManagerApp(ISqlSugarClient client, IAuth auth,
|
||||
RevelanceManagerApp revelanceApp) : base(client, auth)
|
||||
{
|
||||
_revelanceApp = revelanceApp;
|
||||
}
|
||||
|
||||
public string[] GetChairmanId(string[] orgIds)
|
||||
{
|
||||
return Repository.Find(u => orgIds.Contains(u.Id)&&u.ChairmanId!= null).Select(u => u.ChairmanId).ToArray();
|
||||
return SugarClient.Queryable<SysOrg>().Where(u => orgIds.Contains(u.Id) && u.ChairmanId != null).Select(u => u.ChairmanId).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,11 @@ using Microsoft.EntityFrameworkCore;
|
||||
using OpenAuth.App.Request;
|
||||
using OpenAuth.Repository;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
public class RoleApp : BaseStringApp<Role,OpenAuthDBContext>
|
||||
public class RoleApp : SqlSugarBaseApp<Role>
|
||||
{
|
||||
private RevelanceManagerApp _revelanceApp;
|
||||
|
||||
@@ -39,7 +41,7 @@ namespace OpenAuth.App
|
||||
public async Task<PagedListDataResp<Role>> LoadAll(QueryRoleListReq request)
|
||||
{
|
||||
var result = new PagedListDataResp<Role>();
|
||||
var objs = UnitWork.Find<Role>(null);
|
||||
var objs = SugarClient.Queryable<Role>();
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
objs = objs.Where(u => u.Name.Contains(request.key));
|
||||
@@ -59,7 +61,7 @@ namespace OpenAuth.App
|
||||
/// <returns></returns>
|
||||
public List<Role> LoadByIds(string[] ids)
|
||||
{
|
||||
return UnitWork.Find<Role>(u => ids.Contains(u.Id)).ToList();
|
||||
return Repository.GetList(u => ids.Contains(u.Id));
|
||||
}
|
||||
|
||||
|
||||
@@ -68,41 +70,38 @@ namespace OpenAuth.App
|
||||
/// </summary>
|
||||
public void Add(RoleView obj)
|
||||
{
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
{
|
||||
Role role = obj;
|
||||
role.CreateTime = DateTime.Now;
|
||||
UnitWork.Add(role);
|
||||
UnitWork.Save();
|
||||
obj.Id = role.Id; //要把保存后的ID存入view
|
||||
|
||||
//如果当前账号不是SYSTEM,则直接分配
|
||||
var loginUser = _auth.GetCurrentUser();
|
||||
if (loginUser.User.Account != Define.SYSTEM_USERNAME)
|
||||
{
|
||||
_revelanceApp.Assign(new AssignReq
|
||||
{
|
||||
type = Define.USERROLE,
|
||||
firstId = loginUser.User.Id,
|
||||
secIds = new[] {role.Id}
|
||||
});
|
||||
}
|
||||
});
|
||||
SugarClient.Ado.BeginTran();
|
||||
Role role = obj;
|
||||
role.CreateTime = DateTime.Now;
|
||||
Repository.Insert(role);
|
||||
obj.Id = role.Id; //要把保存后的ID存入view
|
||||
|
||||
//如果当前账号不是SYSTEM,则直接分配
|
||||
var loginUser = _auth.GetCurrentUser();
|
||||
if (loginUser.User.Account != Define.SYSTEM_USERNAME)
|
||||
{
|
||||
_revelanceApp.Assign(new AssignReq
|
||||
{
|
||||
type = Define.USERROLE,
|
||||
firstId = loginUser.User.Id,
|
||||
secIds = new[] {role.Id}
|
||||
});
|
||||
}
|
||||
SugarClient.Ado.CommitTran();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除角色时,需要删除角色对应的权限
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
public override void Delete(string[] ids)
|
||||
public new void Delete(string[] ids)
|
||||
{
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
{
|
||||
UnitWork.Delete<Relevance>(u=>(u.RelKey == Define.ROLEMODULE || u.RelKey == Define.ROLEELEMENT) && ids.Contains(u.FirstId));
|
||||
UnitWork.Delete<Relevance>(u=>u.RelKey == Define.USERROLE && ids.Contains(u.SecondId));
|
||||
UnitWork.Delete<Role>(u =>ids.Contains(u.Id));
|
||||
UnitWork.Save();
|
||||
});
|
||||
SugarClient.Ado.BeginTran();
|
||||
SugarClient.Deleteable<Relevance>().Where(u=>(u.RelKey == Define.ROLEMODULE || u.RelKey == Define.ROLEELEMENT) && ids.Contains(u.FirstId)).ExecuteCommand();
|
||||
SugarClient.Deleteable<Relevance>().Where(u=>u.RelKey == Define.USERROLE && ids.Contains(u.SecondId)).ExecuteCommand();
|
||||
SugarClient.Deleteable<Role>().Where(u =>ids.Contains(u.Id)).ExecuteCommand();
|
||||
SugarClient.Ado.CommitTran();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -111,19 +110,16 @@ namespace OpenAuth.App
|
||||
/// <param name="obj"></param>
|
||||
public void Update(RoleView obj)
|
||||
{
|
||||
Role role = obj;
|
||||
|
||||
UnitWork.Update<Role>(u => u.Id == obj.Id, u => new Role
|
||||
Repository.Update(u => new Role
|
||||
{
|
||||
Name = role.Name,
|
||||
Status = role.Status
|
||||
});
|
||||
|
||||
Name = obj.Name,
|
||||
Status = obj.Status
|
||||
}, u => u.Id == obj.Id);
|
||||
}
|
||||
|
||||
|
||||
public RoleApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Role,OpenAuthDBContext> repository,
|
||||
RevelanceManagerApp app,IAuth auth) : base(unitWork, repository, auth)
|
||||
public RoleApp(ISqlSugarClient client,
|
||||
RevelanceManagerApp app,IAuth auth) : base(client, auth)
|
||||
{
|
||||
_revelanceApp = app;
|
||||
}
|
||||
|
||||
@@ -100,6 +100,15 @@ namespace OpenAuth.App.Test
|
||||
Console.WriteLine($"添加数据库连接: {conn.Key} / {(dbtypes.ContainsKey(conn.Key) ? dbtypes[conn.Key] : "未指定类型")},连接字符串:{conn.Value}");
|
||||
}
|
||||
|
||||
//通过ConfigId为空判断是否有默认的连接字符串
|
||||
if(!connectionConfigs.Any(x => x.ConfigId == null))
|
||||
{
|
||||
throw new Exception($"没有找到默认的连接字符串:{Define.DEFAULT_TENANT_ID}");
|
||||
}
|
||||
|
||||
//把connectionConfigs排序,ConfigId为空的放在最前面,即默认的连接字符串必须排最前面
|
||||
connectionConfigs = connectionConfigs.OrderBy(x => x.ConfigId == null ? 0 : 1).ToList();
|
||||
|
||||
var sqlSugar = new SqlSugarClient(connectionConfigs);
|
||||
|
||||
// 配置PostgreSQL数据库处理
|
||||
|
||||
@@ -12,100 +12,120 @@ using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using OpenAuth.Repository.Interface;
|
||||
using SqlSugar;
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
public class UserManagerApp : BaseStringApp<SysUser,OpenAuthDBContext>
|
||||
public class UserManagerApp : SqlSugarBaseApp<SysUser>
|
||||
{
|
||||
private RevelanceManagerApp _revelanceApp;
|
||||
private OrgManagerApp _orgManagerApp;
|
||||
public UserManagerApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<SysUser,OpenAuthDBContext> repository,
|
||||
RevelanceManagerApp app,IAuth auth, OrgManagerApp orgManagerApp) : base(unitWork, repository, auth)
|
||||
public UserManagerApp(ISqlSugarClient client,
|
||||
RevelanceManagerApp app, IAuth auth, OrgManagerApp orgManagerApp) : base(client, auth)
|
||||
{
|
||||
_revelanceApp = app;
|
||||
_orgManagerApp = orgManagerApp;
|
||||
}
|
||||
public SysUser GetByAccount(string account)
|
||||
{
|
||||
return Repository.FirstOrDefault(u => u.Account == account);
|
||||
return SugarClient.Queryable<SysUser>().First(u => u.Account == account);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载用户列表
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="ignoreAuth">是否忽略权限,如果忽略权限,可以获取到所有用户</param>
|
||||
/// <returns></returns>
|
||||
private async Task<PagedListDataResp<UserView>> LoadUsers(QueryUserListReq request, bool ignoreAuth = false)
|
||||
{
|
||||
var loginUser = _auth.GetCurrentUser();
|
||||
var query = SugarClient.Queryable<SysUser>();
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
query = query.Where(u => u.Name.Contains(request.key) || u.Account.Contains(request.key));
|
||||
}
|
||||
|
||||
var orgs = SugarClient.Queryable<SysOrg>();
|
||||
if(!ignoreAuth) //如果没有忽略权限,则只能访问自己所在的机构
|
||||
{
|
||||
var orgIds = loginUser.Orgs.Select(u => u.Id).ToArray();
|
||||
orgs = orgs.Where(u => orgIds.Contains(u.Id));
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(request.orgId)) //如果请求的orgId不为空,加载这个机构及该机构下级的所有用户
|
||||
{
|
||||
var reqorg = SugarClient.Queryable<SysOrg>().First(u => u.Id == request.orgId);
|
||||
var cascadeId = reqorg.CascadeId;
|
||||
var orgIds = orgs.Where(u => u.CascadeId.Contains(cascadeId)).Select(u => u.Id).ToArray();
|
||||
var userIds = SugarClient.Queryable<Relevance>().Where(r => r.RelKey == Define.USERORG
|
||||
&& orgIds.Contains(r.SecondId)).Select(r => r.FirstId).Distinct().ToList();
|
||||
query = query.Where(u => userIds.Contains(u.Id));
|
||||
|
||||
}else{
|
||||
if(!ignoreAuth) //如果没有忽略权限,则根据用户所在的机构获取用户
|
||||
{
|
||||
var orgIds = orgs.Select(o => o.Id).ToArray();
|
||||
var userIds = SugarClient.Queryable<Relevance>().Where(r => r.RelKey == Define.USERORG
|
||||
&& orgIds.Contains(r.SecondId)).Select(r => r.FirstId).Distinct().ToList();
|
||||
query = query.Where(u => userIds.Contains(u.Id));
|
||||
}
|
||||
|
||||
//没有限制权限、没有传入orgId,则query就是获取最原始的所有用户
|
||||
}
|
||||
|
||||
var userOrgs = query
|
||||
.LeftJoin<SysUser>((user, u) => user.ParentId == u.Id)
|
||||
.LeftJoin<Relevance>((user, u, r) => user.Id == r.FirstId && r.RelKey == Define.USERORG)
|
||||
.LeftJoin<SysOrg>((user, u, r, o) => r.SecondId == o.Id);
|
||||
|
||||
var userOrgsResult = userOrgs.Select((user, u, r, o) => new
|
||||
{
|
||||
Account = user.Account,
|
||||
Name = user.Name,
|
||||
Id = user.Id,
|
||||
Sex = user.Sex,
|
||||
Status = user.Status,
|
||||
BizCode = user.BizCode,
|
||||
CreateId = user.CreateId,
|
||||
CreateTime = user.CreateTime,
|
||||
TypeId = user.TypeId,
|
||||
TypeName = user.TypeName,
|
||||
ParentId = user.ParentId,
|
||||
ParentName = u.Name,
|
||||
Key = r.RelKey,
|
||||
OrgId = o.Id,
|
||||
OrgName = o.Name
|
||||
});
|
||||
var userViews = (await userOrgsResult.ToListAsync()).GroupBy(b => b.Account)
|
||||
.Select(u => new UserView
|
||||
{
|
||||
Id = u.First().Id,
|
||||
Account = u.Key,
|
||||
Name = u.First().Name,
|
||||
ParentName = u.First().ParentName,
|
||||
Sex = u.First().Sex,
|
||||
Status = u.First().Status,
|
||||
ParentId = u.First().ParentId,
|
||||
CreateTime = u.First().CreateTime,
|
||||
CreateUser = u.First().CreateId,
|
||||
OrganizationIds = string.Join(",", u.Select(x => x.OrgId)),
|
||||
Organizations = string.Join(",", u.Select(x => x.OrgName))
|
||||
});
|
||||
return new PagedListDataResp<UserView>
|
||||
{
|
||||
Count = userViews.Count(),
|
||||
Data = userViews.OrderBy(u => u.Name)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit).ToList(),
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// 加载当前登录用户可访问的一个部门及子部门全部用户
|
||||
/// 如果请求的request.OrgId为空,则可以获取到已被删除机构的用户(即:没有分配任何机构的用户)
|
||||
/// </summary>
|
||||
public async Task<PagedDynamicDataResp> Load(QueryUserListReq request)
|
||||
public async Task<PagedListDataResp<UserView>> Load(QueryUserListReq request)
|
||||
{
|
||||
var loginUser = _auth.GetCurrentUser();
|
||||
IQueryable<SysUser> query = UnitWork.Find<SysUser>(null);
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
query = UnitWork.Find<SysUser>(u => u.Name.Contains(request.key) || u.Account.Contains(request.key));
|
||||
}
|
||||
var userOrgs = from user in query
|
||||
join user2 in UnitWork.Find<SysUser>(null)
|
||||
on user.ParentId equals user2.Id into tempuser
|
||||
from u in tempuser.DefaultIfEmpty()
|
||||
join relevance in UnitWork.Find<Relevance>(u => u.RelKey == "UserOrg")
|
||||
on user.Id equals relevance.FirstId into temp
|
||||
from r in temp.DefaultIfEmpty()
|
||||
join org in UnitWork.Find<SysOrg>(null)
|
||||
on r.SecondId equals org.Id into orgtmp
|
||||
from o in orgtmp.DefaultIfEmpty()
|
||||
select new
|
||||
{
|
||||
user.Account,
|
||||
user.Name,
|
||||
user.Id,
|
||||
user.Sex,
|
||||
user.Status,
|
||||
user.BizCode,
|
||||
user.CreateId,
|
||||
user.CreateTime,
|
||||
user.TypeId,
|
||||
user.TypeName,
|
||||
user.ParentId,
|
||||
ParentName = u.Name, //直属上级
|
||||
Key = r.RelKey,
|
||||
r.SecondId,
|
||||
OrgId = o.Id,
|
||||
OrgName = o.Name
|
||||
};
|
||||
//如果请求的orgId不为空
|
||||
if (!string.IsNullOrEmpty(request.orgId))
|
||||
{
|
||||
var org = loginUser.Orgs.SingleOrDefault(u => u.Id == request.orgId);
|
||||
var cascadeId = org.CascadeId;
|
||||
var orgIds = loginUser.Orgs.Where(u => u.CascadeId.Contains(cascadeId)).Select(u => u.Id).ToArray();
|
||||
//只获取机构里面的用户
|
||||
userOrgs = userOrgs.Where(u => u.Key == Define.USERORG && orgIds.Contains(u.OrgId));
|
||||
}
|
||||
else //todo:如果请求的orgId为空,即为跟节点,这时可以额外获取到机构已经被删除的用户,从而进行机构分配。可以根据自己需求进行调整
|
||||
{
|
||||
var orgIds = loginUser.Orgs.Select(u => u.Id).ToArray();
|
||||
//获取用户可以访问的机构的用户和没有任何机构关联的用户(机构被删除后,没有删除这里面的关联关系)
|
||||
userOrgs = userOrgs.Where(u => (u.Key == Define.USERORG && orgIds.Contains(u.OrgId)) || (u.OrgId == null));
|
||||
}
|
||||
var userViews = (await userOrgs.ToListAsync()).GroupBy(b => b.Account)
|
||||
.Select(u =>new UserView
|
||||
{
|
||||
Id = u.First().Id,
|
||||
Account = u.Key,
|
||||
Name = u.First().Name,
|
||||
ParentName = u.First().ParentName,
|
||||
Sex = u.First().Sex,
|
||||
Status = u.First().Status,
|
||||
ParentId = u.First().ParentId,
|
||||
CreateTime = u.First().CreateTime,
|
||||
CreateUser = u.First().CreateId,
|
||||
OrganizationIds = string.Join(",", u.Select(x=>x.OrgId))
|
||||
,Organizations = string.Join(",", u.Select(x=>x.OrgName))
|
||||
});
|
||||
return new PagedDynamicDataResp
|
||||
{
|
||||
Count =userViews.Count(),
|
||||
Data =userViews.OrderBy(u => u.Name)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit),
|
||||
};
|
||||
return await LoadUsers(request, false);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取所有的用户
|
||||
@@ -113,128 +133,66 @@ namespace OpenAuth.App
|
||||
/// </summary>
|
||||
public async Task<PagedListDataResp<UserView>> LoadAll(QueryUserListReq request)
|
||||
{
|
||||
IQueryable<SysUser> query = UnitWork.Find<SysUser>(null);
|
||||
if (!string.IsNullOrEmpty(request.key))
|
||||
{
|
||||
query = UnitWork.Find<SysUser>(u => u.Name.Contains(request.key) || u.Account.Contains(request.key));
|
||||
}
|
||||
var userOrgs = from user in query
|
||||
join user2 in UnitWork.Find<SysUser>(null)
|
||||
on user.ParentId equals user2.Id into tempuser
|
||||
from u in tempuser.DefaultIfEmpty()
|
||||
join relevance in UnitWork.Find<Relevance>(u => u.RelKey == "UserOrg")
|
||||
on user.Id equals relevance.FirstId into temp
|
||||
from r in temp.DefaultIfEmpty()
|
||||
join org in UnitWork.Find<SysOrg>(null)
|
||||
on r.SecondId equals org.Id into orgtmp
|
||||
from o in orgtmp.DefaultIfEmpty()
|
||||
select new
|
||||
{
|
||||
user.Account,
|
||||
user.Name,
|
||||
user.Id,
|
||||
user.Sex,
|
||||
user.Status,
|
||||
user.BizCode,
|
||||
user.CreateId,
|
||||
user.CreateTime,
|
||||
user.TypeId,
|
||||
user.TypeName,
|
||||
user.ParentId,
|
||||
ParentName = u.Name, //直属上级
|
||||
Key = r.RelKey,
|
||||
r.SecondId,
|
||||
OrgId = o.Id,
|
||||
OrgName = o.Name
|
||||
};
|
||||
//如果请求的orgId不为空
|
||||
if (!string.IsNullOrEmpty(request.orgId))
|
||||
{
|
||||
userOrgs = userOrgs.Where(u => u.Key == Define.USERORG && u.OrgId == request.orgId);
|
||||
}
|
||||
var userViews = (await userOrgs.ToListAsync()).GroupBy(b => b.Account).Select(u =>new UserView
|
||||
{
|
||||
Id = u.First().Id,
|
||||
Account = u.Key,
|
||||
Name = u.First().Name,
|
||||
Sex = u.First().Sex,
|
||||
Status = u.First().Status,
|
||||
CreateTime = u.First().CreateTime,
|
||||
CreateUser = u.First().CreateId,
|
||||
ParentName = u.First().ParentName,
|
||||
ParentId = u.First().ParentId,
|
||||
OrganizationIds = string.Join(",", u.Select(x=>x.OrgId))
|
||||
,Organizations = string.Join(",", u.Select(x=>x.OrgName))
|
||||
});
|
||||
return new PagedListDataResp<UserView>()
|
||||
{
|
||||
Count = userViews.Count(),
|
||||
Data = userViews.OrderBy(u => u.Name)
|
||||
.Skip((request.page - 1) * request.limit)
|
||||
.Take(request.limit).ToList()
|
||||
};
|
||||
return await LoadUsers(request, true);
|
||||
}
|
||||
public void AddOrUpdate(UpdateUserReq request)
|
||||
{
|
||||
request.ValidationEntity(u => new {u.Account,u.Name, u.OrganizationIds});
|
||||
request.ValidationEntity(u => new { u.Account, u.Name, u.OrganizationIds });
|
||||
if (string.IsNullOrEmpty(request.OrganizationIds))
|
||||
throw new Exception("请为用户分配机构");
|
||||
SysUser requser = request;
|
||||
requser.CreateId = _auth.GetCurrentUser().User.Id;
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
SugarClient.Ado.BeginTran();
|
||||
if (string.IsNullOrEmpty(request.Id))
|
||||
{
|
||||
if (string.IsNullOrEmpty(request.Id))
|
||||
if (SugarClient.Queryable<SysUser>().Any(u => u.Account == request.Account))
|
||||
{
|
||||
if (UnitWork.Any<SysUser>(u => u.Account == request.Account))
|
||||
{
|
||||
throw new Exception("用户账号已存在");
|
||||
}
|
||||
if (string.IsNullOrEmpty(requser.Password))
|
||||
{
|
||||
requser.Password = requser.Account; //如果客户端没提供密码,默认密码同账号
|
||||
}
|
||||
requser.CreateTime = DateTime.Now;
|
||||
UnitWork.Add(requser);
|
||||
request.Id = requser.Id; //要把保存后的ID存入view
|
||||
throw new Exception("用户账号已存在");
|
||||
}
|
||||
else
|
||||
if (string.IsNullOrEmpty(requser.Password))
|
||||
{
|
||||
UnitWork.Update<SysUser>(u => u.Id == request.Id, u => new SysUser
|
||||
{
|
||||
Account = requser.Account,
|
||||
BizCode = requser.BizCode,
|
||||
Name = requser.Name,
|
||||
Sex = requser.Sex,
|
||||
Status = requser.Status,
|
||||
ParentId = request.ParentId
|
||||
});
|
||||
if (!string.IsNullOrEmpty(requser.Password)) //密码为空的时候,不做修改
|
||||
{
|
||||
UnitWork.Update<SysUser>(u => u.Id == request.Id, u => new SysUser
|
||||
{
|
||||
Password = requser.Password
|
||||
});
|
||||
}
|
||||
requser.Password = requser.Account; //如果客户端没提供密码,默认密码同账号
|
||||
}
|
||||
UnitWork.Save();
|
||||
string[] orgIds = request.OrganizationIds.Split(',').ToArray();
|
||||
_revelanceApp.DeleteBy(Define.USERORG, requser.Id);
|
||||
_revelanceApp.Assign(Define.USERORG, orgIds.ToLookup(u => requser.Id));
|
||||
});
|
||||
requser.CreateTime = DateTime.Now;
|
||||
Repository.Insert(requser);
|
||||
request.Id = requser.Id; //要把保存后的ID存入view
|
||||
}
|
||||
else
|
||||
{
|
||||
Repository.Update(u => new SysUser
|
||||
{
|
||||
Account = requser.Account,
|
||||
BizCode = requser.BizCode,
|
||||
Name = requser.Name,
|
||||
Sex = requser.Sex,
|
||||
Status = requser.Status,
|
||||
ParentId = request.ParentId
|
||||
}, u => u.Id == request.Id);
|
||||
if (!string.IsNullOrEmpty(requser.Password)) //密码为空的时候,不做修改
|
||||
{
|
||||
Repository.Update(u => new SysUser
|
||||
{
|
||||
Password = requser.Password
|
||||
}, u => u.Id == request.Id);
|
||||
}
|
||||
}
|
||||
string[] orgIds = request.OrganizationIds.Split(',').ToArray();
|
||||
_revelanceApp.DeleteBy(Define.USERORG, requser.Id);
|
||||
_revelanceApp.Assign(Define.USERORG, orgIds.ToLookup(u => requser.Id));
|
||||
|
||||
SugarClient.Ado.CommitTran();
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除用户,包含用户与组织关系、用户与角色关系
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
public override void Delete(string[] ids)
|
||||
public new void Delete(string[] ids)
|
||||
{
|
||||
UnitWork.ExecuteWithTransaction(() =>
|
||||
{
|
||||
UnitWork.Delete<Relevance>(u =>(u.RelKey == Define.USERROLE || u.RelKey == Define.USERORG)
|
||||
&& ids.Contains(u.FirstId));
|
||||
UnitWork.Delete<SysUser>(u => ids.Contains(u.Id));
|
||||
UnitWork.Save();
|
||||
});
|
||||
SugarClient.Ado.BeginTran();
|
||||
SugarClient.Deleteable<Relevance>().Where(u => (u.RelKey == Define.USERROLE || u.RelKey == Define.USERORG)
|
||||
&& ids.Contains(u.FirstId)).ExecuteCommand();
|
||||
SugarClient.Deleteable<SysUser>().Where(u => ids.Contains(u.Id)).ExecuteCommand();
|
||||
SugarClient.Ado.CommitTran();
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改密码
|
||||
@@ -242,10 +200,10 @@ namespace OpenAuth.App
|
||||
/// <param name="request"></param>
|
||||
public void ChangePassword(ChangePasswordReq request)
|
||||
{
|
||||
Repository.Update(u => u.Account == request.Account, user => new SysUser
|
||||
Repository.Update(u => new SysUser
|
||||
{
|
||||
Password = request.Password
|
||||
});
|
||||
}, u => u.Account == request.Account);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定角色包含的用户列表
|
||||
@@ -254,15 +212,15 @@ namespace OpenAuth.App
|
||||
/// <returns></returns>
|
||||
public async Task<PagedDynamicDataResp> LoadByRole(QueryUserListByRoleReq request)
|
||||
{
|
||||
var users = from userRole in UnitWork.Find<Relevance>(u =>
|
||||
u.SecondId == request.roleId && u.RelKey == Define.USERROLE)
|
||||
join user in UnitWork.Find<SysUser>(null) on userRole.FirstId equals user.Id into temp
|
||||
from c in temp.Where(u =>u.Id != null)
|
||||
select c;
|
||||
var users = SugarClient.Queryable<Relevance>()
|
||||
.Where(u => u.SecondId == request.roleId && u.RelKey == Define.USERROLE)
|
||||
.LeftJoin<SysUser>((userRole, user) => userRole.FirstId == user.Id)
|
||||
.Where((userRole, user) => user.Id != null)
|
||||
.Select((userRole, user) => user);
|
||||
return new PagedDynamicDataResp
|
||||
{
|
||||
Count =await users.CountAsync(),
|
||||
Data =await users.Skip((request.page - 1) * request.limit).Take(request.limit).ToListAsync()
|
||||
Count = await users.CountAsync(),
|
||||
Data = await users.Skip((request.page - 1) * request.limit).Take(request.limit).ToListAsync()
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
@@ -272,15 +230,15 @@ namespace OpenAuth.App
|
||||
/// <returns></returns>
|
||||
public async Task<PagedDynamicDataResp> LoadByOrg(QueryUserListByOrgReq request)
|
||||
{
|
||||
var users = from userOrg in UnitWork.Find<Relevance>(u =>
|
||||
u.SecondId == request.orgId && u.RelKey == Define.USERORG)
|
||||
join user in UnitWork.Find<SysUser>(null) on userOrg.FirstId equals user.Id into temp
|
||||
from c in temp.Where(u =>u.Id != null)
|
||||
select c;
|
||||
var users = SugarClient.Queryable<Relevance>()
|
||||
.Where(u => u.SecondId == request.orgId && u.RelKey == Define.USERORG)
|
||||
.LeftJoin<SysUser>((userOrg, user) => userOrg.FirstId == user.Id)
|
||||
.Where((userOrg, user) => user.Id != null)
|
||||
.Select((userOrg, user) => user);
|
||||
return new PagedDynamicDataResp
|
||||
{
|
||||
Count =await users.CountAsync(),
|
||||
Data =await users.Skip((request.page - 1) * request.limit).Take(request.limit).ToListAsync()
|
||||
Count = await users.CountAsync(),
|
||||
Data = await users.Skip((request.page - 1) * request.limit).Take(request.limit).ToListAsync()
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
@@ -293,13 +251,13 @@ namespace OpenAuth.App
|
||||
{
|
||||
throw new Exception("不能修改超级管理员信息");
|
||||
}
|
||||
Repository.Update(u => u.Account == request.Account, user => new SysUser
|
||||
{
|
||||
Name = request.Name,
|
||||
Sex = request.Sex
|
||||
});
|
||||
Repository.Update(u => new SysUser
|
||||
{
|
||||
Name = request.Name,
|
||||
Sex = request.Sex
|
||||
}, u => u.Account == request.Account);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户的直属上级ID
|
||||
/// </summary>
|
||||
@@ -311,7 +269,7 @@ namespace OpenAuth.App
|
||||
{
|
||||
throw new Exception("超级管理员没有直属上级,请检查配置");
|
||||
}
|
||||
return Repository.FirstOrDefault(u => u.Id == userid).ParentId;
|
||||
return SugarClient.Queryable<SysUser>().First(u => u.Id == userid).ParentId;
|
||||
}
|
||||
|
||||
|
||||
@@ -325,35 +283,31 @@ namespace OpenAuth.App
|
||||
var sql = $@"
|
||||
select u.*
|
||||
from sysuser u
|
||||
join (select distinct SecondId as UserId
|
||||
from Relevance
|
||||
where RelKey = '{Define.INSTANCE_NOTICE_USER}'
|
||||
and FirstId = '{instanceId}'
|
||||
union
|
||||
select distinct FirstId as UserId
|
||||
from Relevance a
|
||||
inner join (select SecondId as RoleId
|
||||
from Relevance
|
||||
where RelKey = '{Define.INSTANCE_NOTICE_ROLE}'
|
||||
and FirstId = '{instanceId}') b on a.SecondId = b.RoleId
|
||||
where RelKey = 'UserRole') userids on u.Id = userids.UserId";
|
||||
var users = UnitWork.FromSql<SysUser>(sql);
|
||||
return users.Select(u=>u.Id).ToList();
|
||||
join (select distinct SecondId as UserId
|
||||
from Relevance
|
||||
where RelKey = '{Define.INSTANCE_NOTICE_USER}'
|
||||
and FirstId = '{instanceId}'
|
||||
union
|
||||
select distinct FirstId as UserId
|
||||
from Relevance a
|
||||
inner join (select SecondId as RoleId
|
||||
from Relevance
|
||||
where RelKey = '{Define.INSTANCE_NOTICE_ROLE}'
|
||||
and FirstId = '{instanceId}') b on a.SecondId = b.RoleId
|
||||
where RelKey = '{Define.USERROLE}') userids on u.Id = userids.UserId";
|
||||
var users = SugarClient.Ado.SqlQuery<SysUser>(sql);
|
||||
return users.Select(u => u.Id).ToList();
|
||||
}
|
||||
|
||||
public List<UserView> LoadByIds(string[] ids)
|
||||
{
|
||||
var users = Repository.Find(u => ids.Contains(u.Id));
|
||||
var users = SugarClient.Queryable<SysUser>().Where(u => ids.Contains(u.Id));
|
||||
|
||||
//获取用户及用户关联的机构
|
||||
var userOrgs = from user in users
|
||||
join relevance in UnitWork.Find<Relevance>(u => u.RelKey == "UserOrg")
|
||||
on user.Id equals relevance.FirstId into temp
|
||||
from r in temp.DefaultIfEmpty()
|
||||
join org in UnitWork.Find<SysOrg>(null)
|
||||
on r.SecondId equals org.Id into orgtmp
|
||||
from o in orgtmp.DefaultIfEmpty()
|
||||
select new
|
||||
var userOrgs = users
|
||||
.LeftJoin<Relevance>((user, r) => user.Id == r.FirstId && r.RelKey == Define.USERORG)
|
||||
.LeftJoin<SysOrg>((user, r, o) => r.SecondId == o.Id)
|
||||
.Select((user, r, o) => new
|
||||
{
|
||||
user.Id,
|
||||
user.Account,
|
||||
@@ -365,21 +319,22 @@ namespace OpenAuth.App
|
||||
user.ParentId,
|
||||
OrgId = o.Id,
|
||||
OrgName = o.Name
|
||||
};
|
||||
});
|
||||
|
||||
var userViews = userOrgs.GroupBy(b => b.Account).Select(u => new UserView
|
||||
var userOrgsList = userOrgs.ToList(); // 先执行ToList()
|
||||
var userViews = userOrgsList.GroupBy(b => b.Account).Select(g => new UserView
|
||||
{
|
||||
Id = u.First().Id,
|
||||
Account = u.Key,
|
||||
Name = u.First().Name,
|
||||
Sex = u.First().Sex,
|
||||
Status = u.First().Status,
|
||||
CreateTime = u.First().CreateTime,
|
||||
CreateUser = u.First().CreateId,
|
||||
ParentName = u.First().ParentId,
|
||||
ParentId = u.First().ParentId,
|
||||
OrganizationIds = string.Join(",", u.Select(x=>x.OrgId))
|
||||
,Organizations = string.Join(",", u.Select(x=>x.OrgName))
|
||||
Id = g.First().Id,
|
||||
Account = g.Key,
|
||||
Name = g.First().Name,
|
||||
Sex = g.First().Sex,
|
||||
Status = g.First().Status,
|
||||
CreateTime = g.First().CreateTime,
|
||||
CreateUser = g.First().CreateId,
|
||||
ParentName = g.First().ParentId,
|
||||
ParentId = g.First().ParentId,
|
||||
OrganizationIds = string.Join(",", g.Select(x => x.OrgId)),
|
||||
Organizations = string.Join(",", g.Select(x => x.OrgName))
|
||||
});
|
||||
|
||||
return userViews.ToList();
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
using Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OpenAuth.App;
|
||||
using OpenAuth.App.Response;
|
||||
using OpenAuth.Repository.Domain;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenAuth.WebApi.Controllers
|
||||
{
|
||||
@@ -79,6 +81,37 @@ namespace OpenAuth.WebApi.Controllers
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有机构
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public Response<List<OrgView>> LoadAll()
|
||||
{
|
||||
var result = new Response<List<OrgView>>();
|
||||
try
|
||||
{
|
||||
result.Data = _app.LoadAll();
|
||||
}
|
||||
catch (CommonException ex)
|
||||
{
|
||||
if (ex.Code == Define.INVALID_TOKEN)
|
||||
{
|
||||
result.Code = ex.Code;
|
||||
result.Message = ex.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Code = 500;
|
||||
result.Message = ex.InnerException != null
|
||||
? "OpenAuth.WebAPI数据库访问失败:" + ex.InnerException.Message
|
||||
: "OpenAuth.WebAPI数据库访问失败:" + ex.Message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除选中的部门及所有的子部门
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace OpenAuth.WebApi.Controllers
|
||||
/// 获取当前登录用户可访问的一个部门及子部门全部用户
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<PagedDynamicDataResp> Load([FromQuery]QueryUserListReq request)
|
||||
public async Task<PagedListDataResp<UserView>> Load([FromQuery]QueryUserListReq request)
|
||||
{
|
||||
return await _app.Load(request);
|
||||
}
|
||||
|
||||
@@ -187,6 +187,15 @@ namespace OpenAuth.WebApi
|
||||
connectionConfigs.Add(config);
|
||||
logger.LogInformation($"添加数据库连接: {conn.Key} / {(dbtypes.ContainsKey(conn.Key) ? dbtypes[conn.Key] : "未指定类型")},连接字符串:{conn.Value}");
|
||||
}
|
||||
|
||||
//通过ConfigId为空判断是否有默认的连接字符串
|
||||
if(!connectionConfigs.Any(x => x.ConfigId == null))
|
||||
{
|
||||
throw new Exception($"没有找到默认的连接字符串:{Define.DEFAULT_TENANT_ID}");
|
||||
}
|
||||
|
||||
//把connectionConfigs排序,ConfigId为空的放在最前面,即默认的连接字符串必须排最前面
|
||||
connectionConfigs = connectionConfigs.OrderBy(x => x.ConfigId == null ? 0 : 1).ToList();
|
||||
|
||||
var sqlSugar = new SqlSugarClient(connectionConfigs);
|
||||
|
||||
|
||||
@@ -3,12 +3,17 @@ title: 多数据库
|
||||
createTime: 2025/04/23 21:03:10
|
||||
permalink: /core/multidbs/
|
||||
---
|
||||
::: tip 提示
|
||||
* 多数据库指一个应用程序同时连接和操作多个不同的数据库。
|
||||
* 多租户是架构设计模式,用户登录时选择租户信息,后面就只能访问该租户对应的数据库,即只访问一个数据库。
|
||||
|
||||
:::
|
||||
|
||||
框架支持同时访问多个数据库。具体操作如下:
|
||||
|
||||
## 添加新连接字符串
|
||||
|
||||
在配置文件appsettings.json中,添加新的连接字符串`OpenAuthDBContext2`
|
||||
在配置文件appsettings.json中,添加新的连接字符串 `OpenAuthDBContext2`
|
||||
|
||||
```csharp
|
||||
"ConnectionStrings": {
|
||||
@@ -29,7 +34,8 @@ permalink: /core/multidbs/
|
||||
|
||||
### 新建数据库访问基类
|
||||
|
||||
在项目OpenAuth.App中,新建数据库访问基类,比如`SqlSugarApp2`
|
||||
在项目OpenAuth.App中,新建数据库访问基类,比如 `SqlSugarApp2`
|
||||
|
||||
```csharp
|
||||
namespace OpenAuth.App
|
||||
{
|
||||
@@ -60,7 +66,7 @@ namespace OpenAuth.App
|
||||
obj.Application = Assembly.GetEntryAssembly().FullName.Split(',')[0];
|
||||
Repository.Insert(obj);
|
||||
}
|
||||
|
||||
|
||||
public void Update(SysLog obj)
|
||||
{
|
||||
Repository.Update(u => new SysLog
|
||||
@@ -82,7 +88,7 @@ namespace OpenAuth.App
|
||||
|
||||
### 添加数据上下文
|
||||
|
||||
在OpenAuth.Repository中添加新的数据库上下文,比如`OpenAuthDBContext2`
|
||||
在OpenAuth.Repository中添加新的数据库上下文,比如 `OpenAuthDBContext2`
|
||||
|
||||
```csharp
|
||||
public partial class OpenAuthDBContext2 : DbContext
|
||||
@@ -119,7 +125,7 @@ namespace OpenAuth.App
|
||||
|
||||
### 注入新数据库
|
||||
|
||||
在项目OpenAuth.WebApi的启动代码`Startup.cs`中,把`ConfigureServices`方法中注入刚刚添加的数据库上下文
|
||||
在项目OpenAuth.WebApi的启动代码 `Startup.cs`中,把 `ConfigureServices`方法中注入刚刚添加的数据库上下文
|
||||
|
||||
```csharp
|
||||
services.AddDbContext<OpenAuthDBContext2>();
|
||||
|
||||
@@ -4,6 +4,12 @@ createTime: 2025/04/23 21:03:10
|
||||
permalink: /core/multitenant/
|
||||
---
|
||||
|
||||
::: tip 提示
|
||||
* 多数据库指一个应用程序同时连接和操作多个不同的数据库。
|
||||
* 多租户是架构设计模式,用户登录时选择租户信息,后面就只能访问该租户对应的数据库,即只访问一个数据库。
|
||||
|
||||
:::
|
||||
|
||||
目前市面上主流的多租户方案有三种:
|
||||
|
||||
1. **独立数据库** 即为不同的租户提供独立的数据库。
|
||||
|
||||
Reference in New Issue
Block a user