This commit is contained in:
yubaolee
2023-08-11 17:47:02 +08:00
parent 2968aa27a2
commit 65dfe66dda
73 changed files with 3655 additions and 0 deletions

2
docs/core/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,2 @@
{
}

74
docs/core/README.md Normal file
View File

@@ -0,0 +1,74 @@
![LOGO](/logocore.png "1.png")
OpenAuth.Net是基于 **.Net Core/.Net 5** 的开源权限工作流快速开发框架。框架汲取Martin Fowler企业级应用开发思想及全新技术组合IdentityServer、EF core、Quartz、AutoFac、WebAPI、Swagger、Mock、NUnit、VUE、Element-ui等核心模块包括组织机构、角色用户、权限授权、表单设计、工作流等。
如果你想了解企业版的内容,请访问:[http://doc.openauth.net.cn/pro](http://doc.openauth.net.cn/pro/)
::: tip 提示
gitee上面两个版本仅SDK的版本不同代码完全相同。其中
* [OpenAuth.Net](https://gitee.com/dotnetchina/OpenAuth.Net) 的SDK版本为5.0.100,推荐使用该版本
* [OpenAuth.Core](https://gitee.com/yubaolee/OpenAuth.Core) 的SDK版本为.Net Core 3.1.100,历史原因暂且保留,未来的某天会关闭它
.Net目前SDK升级特别方便只需花费3分钟时间既可升级到.Net 6/7/8...等。请参考:[3分钟的时间把.net core 3.1的升级到.NET 5](https://www.cnblogs.com/yubaolee/p/Net3ToNet5.html)所以不要纠结SDK版本问题。
:::
## 技术栈
![](https://img.shields.io/badge/release-2.0-blue)
![](https://img.shields.io/badge/.net%20core-3.1.100-blue)
![](https://img.shields.io/badge/.Net-5.0-blue)
![](https://img.shields.io/badge/IdentityServer4-3.0.1-blue)
![](https://img.shields.io/badge/quartz-3.0.7-blue)
![](https://img.shields.io/badge/Autofac-5.1.2-blue)
![](https://img.shields.io/badge/NUnit-3.12-blue)
![](https://img.shields.io/badge/SwaggerUI-OAS%203.0-blue)
![](https://img.shields.io/badge/Moq-4.13-blue)
![](https://img.shields.io/badge/log4net-2.0.8-blue)
![](https://img.shields.io/badge/AutoMapper-9.0-blue)
![](https://img.shields.io/badge/vue-2.6.10-brightgreen)
![](https://img.shields.io/badge/element--ui-2.10.1-brightgreen)
![](https://img.shields.io/badge/node-%3E%3D14.0-brightgreen)
![](https://img.shields.io/badge/npm-6.14-brightgreen)
![](https://img.shields.io/badge/layui-2.5.6-brightgreen)
## 核心看点
* 支持.net core sdk 3.1.100 及.Net 5[一分钟从.net core 3.1切换至.Net 5](https://www.cnblogs.com/yubaolee/p/Net3ToNet5.html)
* 超强的自定义权限控制功能,请参考:[通用权限设计与实现](https://www.cnblogs.com/yubaolee/p/DataPrivilege.html)
* 完整的字段权限控制可以控制字段可见及API是否返回字段值
* 可拖拽的表单设计
* 可视化流程设计
* 基于Quartz.Net的定时任务控制,可随时启/停可视化配置Cron表达式功能
* 基于CodeSmith的代码生成功能可快速生成带有头/明细结构的页面
* 支持sqlserver、mysql、Oracle(已集成驱动,但无Oracle脚本可以利用工具把其他数据库的数据导过来理论上支持所有数据库
* 支持同时访问多数据源
* 支持多租户
* 集成IdentityServer4实现基于OAuth2的登录体系
* 建立三方对接规范,已有系统可以无缝对接流程引擎
* 前端采用 vue + layui + elementUI + ztree + gooflow + leipiformdesign
* 后端采用 .net core +EF core+ autofac + quartz +IdentityServer4 + nunit + swagger
* 设计工具 PowerDesigner + Enterprise Architect

46
docs/core/apiauth.md Normal file
View File

@@ -0,0 +1,46 @@
# API权限控制
在使用OpenAuth.WebApi过程中系统会对所有的Api进行权限控制。如果没有登录就访问Api接口会提示下面信息
```javascript
{
"message": "认证失败,请提供认证信息",
"code": 401
}
```
如果想正常调用,必需先调用登录接口`/api/Check/Login`拿到登录`token`,如下:
```javascript
{
"returnUrl": "http://localhost:56813",
"token": "e4a5aa00",
"result": null,
"message": "操作成功",
"code": 200
}
```
把token值放置在http header X-Token中即可正常调用其他接口。如下
```javascript
GET /api/Applications/Load?page=1&limit=10 HTTP/1.1
Host: localhost:52789
X-Token: e4a5aa00
```
## 不登录直接访问
有些场景我们需要不进行登录直接访问接口,可以直接在接口上面加[AllowAnonymous]注解即可。如下:
```csharp
[HttpGet]
[AllowAnonymous]
public async Task<TableData> Load([FromQuery]QueryWmsInboundOrderDtblListReq request)
{
return await _app.Load(request);
}
```

61
docs/core/cache.md Normal file
View File

@@ -0,0 +1,61 @@
# 缓存机制
## 服务器缓存
在OpenAuth中缓存通过`ICacheContext`接口实现的。系统有三个实现方式:
* 基于.net自带的`MemoryCache`实现的`CacheContext`
* 基于`StackExchange.Redis`实现的`RedisCacheContext`【新增💪】
* 基于`Enyim Memcache`实现的`EnyimMemcachedContext`
可以根据自己需要扩展其他缓存。OpenAuth.Mvc和OpenAuth.Api默认使用的是CacheContext。可以在`AutofacExt.cs`跟换自己喜欢的缓存:
```csharp
public static void InitAutofac(ContainerBuilder builder)
{
...
//更换缓存
builder.RegisterType(typeof(CacheContext)).As(typeof(ICacheContext));
}
```
## 服务器缓存有效时间
服务器默认缓存时间为10天`LoginParse.cs`中设置
```csharp
_cacheContext.Set(currentSession.Token, currentSession, DateTime.Now.AddDays(10));
```
::: warning 注意事项1
默认使用的是.net的内存Cache在用IIS发布后由于IIS本身存在自动回收的机制会导致系统缓存20分钟就会失效。
:::
::: warning 注意事项2
如果使用Redis缓存注意调整配置文件中关于redis的配置
```csharp
"AppSetting": {
//其他配置..
"RedisConf": "your_redis_server:6379,password=your_redis_password" //redis配置信息
}
```
:::
## 企业版前端缓存
企业版前端使用js-cookie存储登录token信息。默认为`session cookie`也就是这个session在关闭浏览器后会被删除。如果想延长登录有效期限可以调整`src\utils\auth.js`中写入cookie的时间
```javascript
//设置登录有效期为7天
export function setToken(token) {
return Cookies.set(TokenKey, token, { expires: 7 })
}
```

154
docs/core/changelog.md Normal file
View File

@@ -0,0 +1,154 @@
# 版本发布
### v4.0
* 【新增】集成Variant Form - 可视化低代码表单;
* 【新增】完成vue3 setup模式单表代码生成
### v3.3
* 【新增】流程表单项增加读写权限控制;
* 【新增】代码生成器增加主从表生成;
* 【新增】代码生成器设置可以控制界面展示;
* 【新增】流程处理增加消息通知;
* 【新增】优化swagger分组
### v3.2
* 【新增】在swagger界面查看接口调用时间及SQL执行时间; [查看使用说明](http://doc.openauth.net.cn/core/log.html#%E5%9C%A8swagger%E4%B8%AD%E8%BE%93%E5%87%BA%E6%97%A5%E5%BF%97 )
* 【新增】swagger接口分组;
* 【新增】流程编辑功能(草稿或驳回状态时);
* 【新增】流程召回功能;
* 【新增】运行时选定执行人、执行角色功能;
* 【新增】自定义模态验证异常返回信息;
* 【新增】配置启动端口;
### v3.1
* 【新增】Oracle数据库驱动
* 【新增】流程召回功能
* 【新增】调整APP层文件结构按功能划分
* 【新增】支持同时配置多个类型数据库的连接字符串,详见:[这里](http://doc.openauth.net.cn/core/multidbs.html)
### v3.0
* 【新增】多数据源支持
* 【新增】提供全新的事务接口方式
* 【新增】新增异步接口
* 【新增】新增灵活的API提交数据验证
* 【新增】新增附件管理,上传图片支持生成缩略图
* 【新增】调整代码生成器把CodeSmith改为站内代码生成
### v2.1
* 【新增】为角色分配用户
* 【新增】为部门分配用户
### v2.0
* 【新增】框架升级至.net core sdk 3.1.100
* 【新增】增加`个人中心`页面,可修改个人信息及切换当前默认部门
* 【优化】升级layui至2.5.6
* 【优化】可以灵活配置用户可访问的机构数据权限
* 【优化】优化会签功能呢
* 【优化】优化角色添加自动关联当前登录用户
### v1.6
* 【优化】优化导航排序、支持多级导航
* 【优化】企业版启用全新登录界面;
* 【新增】启用数据字典功能;
* 【新增】日志及用户消息板块;
* 【新增】企业版代码生成器,可以快速生成带有头/明细结构的页面;
* 【新增】数据权限控制,超强的自定义权限控制功能。详见:[这里](https://www.cnblogs.com/yubaolee/p/DataPrivilege.html)
* 【新增】完整的字段权限控制可以控制字段可见及API是否返回字段值
### v1.5
* 【优化】升级layui至2.5.4
* 【优化】流程处理页面展示流转记录;
* 【优化】流程支持角色审批;
* 【新增】集成IdentityServer4实现基于OAuth2的登录体系
* 【新增】建立三方对接规范,已有系统可以无缝对接流程引擎;
### v1.4
* 【优化】升级layui至2.4.5
* 【优化】升级vue至2.6.10
* 【优化】全面重写界面初始化交互优化layui与vue数据初始读取
* 【新增】全面实现数据字段权限控制。针对自定义模块,可以为角色分配可见字段;
* 【新增】模块可隐藏功能,只授权,但不在导航栏显示;
### v1.3
* 基于.Net Core 2.1开发;
* 全面支持sqlserver、mysql数据库
* 全面实现模块控制、菜单控制;
* 完整的代码生成器pro版本提供;
* 前端采用 vue + gooflow + leipiformdesign
* 后端采用 asp.net mvc core 2.1 + EF core+ autofac + json.net
* 代码生成工具 CodeSmith
* 设计工具 PowerDesigner + Enterprise Architect
### OpenAuth.Net 4.0 颠覆版(2018-)
* 版本重构,最重要的一个版本;
* 前后端完全分离,结构更加清晰。`我们不限制规则,只用主流的技术构建强大的框架`
* 前端采用 vue + layui + ztree + gooflow + leipiformdesign
* 后端采用 asp.net mvc + Web API + EF + autofac + swagger + json.net
* 代码生成工具 CodeSmith
* 设计工具 PowerDesigner + Enterprise Architect

View File

@@ -0,0 +1,3 @@
# 数据权限
关于数据权限控制,可以详细查看博文:[通用权限设计与实现](https://www.cnblogs.com/yubaolee/p/DataPrivilege.html)

View File

@@ -0,0 +1,86 @@
# 字段权限
::: warning 注意
字段权限只针对【非系统模块】有效即在添加新模块的时候需要设置模块属性“是否系统”为false。
:::
## 使用场景
字段权限控制分为两种:
1. 直接不返回字段的值。用于敏感数据不向客户端反馈。
1. 返回字段的值但界面不显示。常常用于数据需要和后端交互但不想在界面显示比如各种Id。这种直接在返回实体增加`[Browsable(false)]`注解即可。
## 如何做?
### 后端代码处理
针对场景1在做返回处理的时候需要过滤数据库查询字段如下本文以Resource表为例
```csharp
var columnFields = loginContext.GetTableColumnsFromDb("Resource");
if (columnFields == null || columnFields.Count == 0)
{
throw new Exception("未找到Resource表的字段属性");
}
var propertyStr = string.Join(',', columnFields.Select(u => u.ColumnName));
result.columnFields = columnFields;
result.data = resources.OrderBy(u => u.TypeId)
.Skip((request.page - 1) * request.limit)
.Take(request.limit).Select($"new ({propertyStr})");
result.count = await resources.CountAsync();
return result;
```
::: warning 注意
因为开源版没有代码生成器所以需要直接从数据读取表的字段结构使用的是loginContext.GetTableColumnsFromDb获取可访问的字段
:::
### 前端代码处理
在做表格的时候需要使用动态列。以`Views/Resources/index.cshtml`为例,如下:
```HTML
<table class="layui-table" id="mainList"
lay-data="{height: 'full-80', page:true, id:'mainList'}"
lay-filter="list" lay-size="sm">
</table>
```
在用户自定义的脚本`wwwroot/userJs/resources.js`中,动态加载列:
```javascript
//加载表头
$.getJSON('/Resources/Load',
{ page: 1, limit: 1 },
function (data) {
var columns = data.columnFields.filter(u => u.IsList ===true).map(function (e) {
return {
field: e.ColumnName,
title: e.Comment
};
});
columns.unshift({
type: 'checkbox',
fixed: 'left'
});
table.render({
elem: '#mainList',
page: true,
url: '/Resources/Load',
cols: [columns]
, response: {
statusCode: 200 //规定成功的状态码默认0
}
});
});
```
### 运行界面配置
完成代码编写后,在【基础配置】--【角色管理】--【为角色分配模块】最后为角色分配【可见字段】中分配权限
![](/roleassignproperty.png)

View File

@@ -0,0 +1,58 @@
# WebApi请求验证
框架提供灵活的实体模型验证功能。可以方便地对实体进行验证。只需两步即可:
## 增加注解
在请求参数中添加验证注解
```csharp
namespace OpenAuth.App.Request
{
public class UpdateUserReq
{
/// <summary>
/// </summary>
/// <returns></returns>
[Required(ErrorMessage = "账号肯定不能为空啊~~")]
public string Account { get; set; }
/// <summary>
/// 用户姓名
/// </summary>
/// <returns></returns>
[Required(ErrorMessage="姓名不能为空")]
public string Name { get; set; }
/// <summary>
/// 所属组织Id多个可用分隔
/// </summary>
/// <value>The organizations.</value>
[Required(ErrorMessage = "请为用户分配机构")]
public string OrganizationIds { get; set; }
...
}
}
```
## 业务代码中验证
在OpenAuth.App中调用验证
```csharp
namespace OpenAuth.App
{
public class UserManagerApp : BaseApp<User,OpenAuthDBContext>
{
public void AddOrUpdate(UpdateUserReq request)
{
//验证Account/Name/OrganizationIds
request.ValidationEntity(u => new {u.Account,u.Name, u.OrganizationIds});
...//其他代码略
}
}
}
```

79
docs/core/deploy.md Normal file
View File

@@ -0,0 +1,79 @@
# 部署MVC
::: tip 提示
因.net core内部有自托管的Web服务器推荐使用控制台方式部署。本内容基于控制台命令的方式。如果部署到IIS请自行百度:cold_sweat:
:::
## 生成发布文件
* 修改部署环境的连接字符串信息,特别注意是`appsettings.Production.json`文件:
![说明](/configmvc.png "说明")
::: warning 注意
决定系统部署后读取`appsettings.json`还是`appsettings.Production.json`是通过操作系统的环境变量`ASPNETCORE_ENVIRONMENT`来控制的。
在centos切换成正式可以用
```shell
export ASPNETCORE_ENVIRONMENT=Production
```
或者修改/etc/profile配置在结尾添加
```shell
ASPNETCORE_ENVIRONMENT=Production
export ASPNETCORE_ENVIRONMENT
```
然后刷新:
```shell
source /etc/profile
```
在Widows系统中增加对应环境变量即可
:::
* 直接在解决方案资源管理器中选中OpenAuth.Mvc右键【发布】出现下面的配置框使用文件系统即可
![说明](http://pj.openauth.net.cn/zentao/file-read-8.png "说明")
* 发布完成后可以在输出目录看到发布详情(红色框内即为发布的文件夹):
![说明](http://pj.openauth.net.cn/zentao/file-read-69.png "说明")
## 部署OpenAuth.Mvc
将发布后的文件拷贝到服务器文件夹。直接使用`dotnet openauth.mvc.dll` 命令启动。启动成功后使用浏览器打开http://localhost:1802 即可访问,如下图所示:
![说明](/mvcmain.png "说明")
## jenkins部署OpenAuth.Mvc
OpenAuth.Core采用的是gitee托管源码只需使用Gitee WebHook构建触发器。配置如下
![说明](/giteesource.png "说明")
做好上面的配置后代码提交时就会触发jenkins工作。剩下的就是编写自己的构建脚本。增加构建步骤选择执行Shell。并输入以下脚本
```shell
#!/bin/bash
kill -9 $(ps -ef|grep OpenAuth.Mvc.dll|grep -v grep|awk '{print $2}')
#项目启动之后才不会被Jenkins杀掉。
export BUILD_ID=dontKillMe
pwd
echo $PATH
dotnet restore # 还原nuget包
cd ./OpenAuth.Mvc
dotnet build # 编译
rm -rf /data/openauthmvc #最终站点路径
mkdir /data/openauthmvc
dotnet publish -c:Release -o /data/openauthmvc # 生成发布文件到/data/openauthmvc
nohup dotnet /data/openauthmvc/OpenAuth.Mvc.dll &
echo '============================end build======================================='
```

87
docs/core/deployapi.md Normal file
View File

@@ -0,0 +1,87 @@
# 部署API
## 生成发布文件
* 修改部署环境的连接字符串信息,特别注意是`appsettings.Production.json`文件:
![20220101232738](http://img.openauth.net.cn/20220101232738.png)
::: warning 注意
决定系统部署后读取`appsettings.json`还是`appsettings.Production.json`是通过操作系统的环境变量`ASPNETCORE_ENVIRONMENT`来控制的。
在centos切换成正式可以用
```shell
export ASPNETCORE_ENVIRONMENT=Production
```
或者修改/etc/profile配置在结尾添加
```shell
ASPNETCORE_ENVIRONMENT=Production
export ASPNETCORE_ENVIRONMENT
```
然后刷新:
```shell
source /etc/profile
```
在Widows系统中增加对应环境变量即可
:::
* 直接在解决方案资源管理器中选中OpenAuth.WebApi右键【发布】出现下面的配置框使用文件系统即可
![20220101232912](http://img.openauth.net.cn/20220101232912.png)
* 发布完成后可以在输出目录看到发布详情(红色框内即为发布的文件夹):
![20220101233049](http://img.openauth.net.cn/20220101233049.png)
* 将Debug目录中的OpenAuth.WebApi.xml拷贝到发布文件夹publish:
![20220101235436](http://img.openauth.net.cn/20220101235436.png)
## 部署OpenAuth.WebApi
将发布后的文件拷贝到服务器文件夹。直接使用`dotnet OpenAuth.WebApi.dll` 命令启动。启动成功后使用浏览器打开[http://localhost:52789/swagger/index.html](http://localhost:52789/swagger/index.html) 即可访问,如下图所示:
![20220101233542](http://img.openauth.net.cn/20220101233542.png)
## jenkins部署OpenAuth.WebApi
OpenAuth.Core采用的是gitee托管源码只需使用Gitee WebHook构建触发器。配置如下
![说明](/giteesource.png "说明")
做好上面的配置后代码提交时就会触发jenkins工作。剩下的就是编写自己的构建脚本。增加构建步骤选择执行Shell。并输入以下脚本
```shell
#!/bin/bash
kill -9 $(ps -ef|grep OpenAuth.WebApi.dll|grep -v grep|awk '{print $2}')
#export BUILD_ID=dontKillMe这一句很重要这样指定了项目启动之后才不会被Jenkins杀掉。
export BUILD_ID=dontKillMe
pwd
echo $PATH
dotnet restore
cd ./OpenAuth.WebApi
pwd
echo '============================begin build======================================='
dotnet build # 为了生成XML注释文件 用于swagger注释
rm -rf /data/openauthapi
mkdir /data/openauthapi
cp ./bin/Debug/netcoreapp3.1/OpenAuth.Repository.xml /data/openauthapi/
cp ./bin/Debug/netcoreapp3.1/OpenAuth.App.xml /data/openauthapi/
cp ./bin/Debug/netcoreapp3.1/Infrastructure.xml /data/openauthapi/
dotnet publish -c:Release -o /data/openauthapi # 如果针对给定运行时发布项目带上-r 如:-r centos.7-x64
nohup dotnet /data/openauthapi/OpenAuth.WebApi.dll &
#cp ./bin/Debug/netcoreapp2.0/您的项目路径.xml $WORKSPACE/jenkins_publish/ # 拷贝swagger注释
echo '============================end build======================================='
```

80
docs/core/devnew.md Normal file
View File

@@ -0,0 +1,80 @@
# 添加新模块
## 前言
OpenAuth.Mvc添加新模块的方式非常简单完全可以参考系统已有的`资源管理`模块编写相应的代码。参考的`资源管理`功能对应的代码如下:
![](http://pj.openauth.net.cn/zentao/file-read-55.png)
如果我们想新加一个仓储管理的模块,模块标识为`Stock`。那么需要添加的文件如下:
├─OpenAuth.Mvc
│ ├─ Controllers
│ │ └─ StocksController.cs
│ ├─ Views
│ │ └─ Stocks
│ │ └─ index.cshtml
│ ├─ wwwroot
│ │ └─ userJs
│ │ └─ stock.js
├─OpenAuth.App
│ ├─ StockApp.cs
│ ├─ Request
│ │ └─ QueryStockReq.cs
├─ OpenAuth.Repository
│ ├─ OpenAuthDBContext.cs
│ ├─ Domain
│ └─ Stock.cs
当然全部手撸这些代码还是会疯的。用户可以直接使用项目`CodeSmith`文件夹里面的模板一键生成上述代码。而且CodeSmith模板本身也是全部源码可以根据自己需求调整生成的内容。
## 工具准备
CodeSmith Generator Studio 8.0或以上
数据库OpenAuthDB中添加仓储表【Stock】本文以该数据表为例
## 添加实体
如下图使用CodeSmith文件夹中的模板右击【ApiGenerate.cst】--【Execute】选择需要生成的表本文以Stock为例及相关的上下文命名空间点击【Generate】
![](http://pj.openauth.net.cn/zentao/file-read-26.jpg)
生成成功后在CodeSmith/Csharp文件夹下面会有Stock实体相关文档如下图
![](http://pj.openauth.net.cn/zentao/file-read-53.png)
把CSharp\OpenAuth.App覆盖到自己项目对应目录
把CSharp\OpenAuth.Repository\Domain覆盖到自己项目对应目录
**把CSharp\OpenAuth.Repository\OpenAuthDBContext.cs中的内容添加到自己项目的文件中千万不要直接覆盖文件**
**其他文件夹的内容为WebAPI项目使用可以不管。**
## 添加界面
如下图使用CodeSmith文件夹中的模板右击【WebGenerate.cst】--【Execute】选择需要生成的表本文以Stock为例及相关的上下文命名空间点击【Generate】
![](http://pj.openauth.net.cn/zentao/file-read-47.png)
生成成功后在CodeSmith/Csharp文件夹下面会有相关的界面代码如下图
![](http://pj.openauth.net.cn/zentao/file-read-50.png)
Controllers、Views直接覆盖到OpenAuth.Mvc项目中对应的文件夹即可
userJs直接覆盖到OpenAuth.Mvc/wwwroot中
## 添加模块
编写完上面代码后运行系统使用System账号登录系统在【模块管理】中添加`仓储管理`模块并为它添加菜单这里我只添加一个菜单【btnAdd】如下图
![](http://pj.openauth.net.cn/zentao/file-read-51.png)
重新登录系统,即可看到新加的仓储管理模块。
![](http://pj.openauth.net.cn/zentao/file-read-52.png)

127
docs/core/entity.md Normal file
View File

@@ -0,0 +1,127 @@
# 数据库实体
## 更换主键名称
系统默认的主键是以`Id`命名,如果数据库主键是其他名称,可以直接用注解进行更改:
```csharp
[Column("CustomerId")]
public string Id { get; set; }
```
## 如何添加主键类型为numberic的业务代码
如果数据库表中存在其他类型的主键,可以通过继承`BaseEntity`实现。目前系统默认有三个实体基类:
- `StringEntity`针对数据库主键为varchar类型的数据表,主键按guid方式生成;
- `LongEntity`针对数据库主键为numberic(15)的数据表,主键按雪花算法生成;【新功能,官方推荐使用方式👍】
- `IntAutoGenEntity`针对数据库主键为numberic且为数据库自动生成的类型表通常为SqlServer的自动增长类型和Oracle的Sequence生成【新功能】
这三个基类可以覆盖90%以上的业务场景。如果这两个不能满足需求,可以自己按需求扩展。参考代码如下:
```csharp
/// <summary>
/// 数据库Id为int类型的数据实体使用该基类用法同Entity
/// </summary>
public class IntEntity :BaseEntity
{
[Browsable(false)]
public int Id { get; set; }
public override bool KeyIsNull()
{
return Id == 0;
}
/// <summary>
/// 需要自己有个生成随机ID的算法可参考LongEntity中的雪花算法
/// </summary>
public override void GenerateDefaultKeyVal()
{
Id = RandomInt();
}
}
```
## 具体如何做
我们以一个主键为numeric(16)的表表名为LongTable为例
```SQL
create table LongTable
(
Id numeric(16) not null
constraint LongTable_pk
primary key nonclustered,
Name varchar(50)
)
go
```
1. 首先创建对应的业务实体。在`OpenAuth.Repository.Domain`中添加:
```csharp
namespace OpenAuth.Repository.Domain
{
[Table("LongTable")]
public class LongTable :LongEntity
{
public string Name { get; set; }
}
}
```
2. 修改`OpenAuth.Repository.OpenAuthDBContext`,增加成员变量:
```csharp
public virtual DbSet<LongTable> IntTables { get; set; }
```
3. 最后创建对应的业务层代码。在`OpenAuth.App`中添加:
```csharp
namespace OpenAuth.App
{
/// <summary>
/// 主键为numberic类型的业务使用BaseLongApp基类
/// </summary>
public class LongTableApp :BaseLongApp<LongTable, OpenAuthDBContext>
{
public void Add(LongTable application)
{
Repository.Add(application);
}
public void Update(LongTable application)
{
Repository.Update(application);
}
public async Task<List<LongTable>> GetList(QueryAppListReq request)
{
var applications = UnitWork.Find<LongTable>(null) ;
return applications.ToList();
}
public LongTableApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<LongTable,OpenAuthDBContext> repository,IAuth auth)
: base(unitWork, repository, auth)
{
}
}
}
```
然后就可以像其他应用服务一样使用这个服务
::: warning 注意
最新版才支持以前的版本2.0或以前的版本可以参考BaseEntity进行改造
:::

108
docs/core/faq.md Normal file
View File

@@ -0,0 +1,108 @@
# 常见问题处理
## 注释的使用
在Controller返回给前端的字段上通常会有两个“注释”如下
```csharp
/// <summary>
/// 用户登录帐号
/// </summary>
[Description("用户登录帐号")]
public string Account { get; set; }
```
开发者在使用的时候会觉得多余。但他们的用途不同:
* /// 注释是真正的代码注释用于方便读取代码并为swagger提供字段解释
* Description注解是当前端表格需要动态表头时返回的表头中文说明
## 项目显示不可用
![](/notavailable.png)
这种情况一般是开发工具或SDK的版本号不对。严格按照下面的提示打开项目
* v2.0及以后版本因使用.net core 3.1必须使用visual Studio 2019及以上版本打开
* v2.0以前的版本可以使用visual Studio 2017 及.net core 2.1.4
## 系统使用Sql Server 2008数据库的问题
在使用Sql Server 2008时会提示下面错误
> System.Data.SqlClient.SqlException:“'OFFSET' 附近有语法错误。在 FETCH 语句中选项 NEXT 的用法无效。
因为SQL SERVER 2008 不支持FETCH分页方式所以需要在startup.cs中修改配置
```csharp
optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=OpenAuthDB;User=sa;Password=123456;Integrated Security=True;",
b => b.UseRowNumberForPaging());
```
即使用rownumber的分页方式。 当然最好的解决方式是升级SQL SERVER到2012或以上版本。
::: warning 注意
OpenAuth.Core 2.0及以后版本因为使用了.net core 3.1该SDK已经放弃了这种方式因此只能通过升级Sql Server的方式解决该问题
:::
## 使用mysql时提示无法找到openauthdb.Org
在linux下面mysql是区分数据库大小写的但OpenAuth.Core使用EF映射数据库表是按照首字母大写来处理的。在mysql配置中里面加上
```shell
lower_case_table_names=1
```
从而不区分大小写,即可解决该问题
## WebApi里增加一个控制器,Swagger不显示
需要在控制器上面添加注释,如:
```csharp
/// <summary> 文件上传</summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class FilesController :ControllerBase
```
## 实体没有主键
定义一个实体有时会出现没有主键的问题即提示“Unable to track an instance of type xxxx because it does not have a primary key.”,这时可以强制在`OpenAuthDbContext.cs`中指定一个主键,如下:
```csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DataPrivilegeRule>()
.HasKey(c => new { c.Id });
}
```
## 新添加数据,马上执行【删除】,不能删除数据库记录
原因新增记录时没有返回新增数据的ID信息导致删除不成功。
#### 解决方法一
重新加载列表,直接把 this.list.unshift(this.temp)换成this.getList()。如下:
```javascript
createData() {
// 保存提交
this.$refs['dataForm'].validate((valid) => {
if (valid) {
categorys.add(this.temp).then(() => {
this.getList();
...
})
}
})
},
```
#### 解决方法二
执行添加后把Id返回给前端界面。详情请参考网友博客[OpenAuth.net入门【5】——解决添加完数据在未刷新列表时执行删除数据未被真正删除的问题](https://www.cnblogs.com/wjx-blog/p/15892811.html)

53
docs/core/flowinstance.md Normal file
View File

@@ -0,0 +1,53 @@
# 基本操作
一个完整的工作流包括流程设计及流程实例处理。分别对应系统中【基础配置/流程设计】及【流程中心】两个板块。具体包含以下几个步骤:
1. 在【基础配置/表单设计】中添加一个用于流程的表单开源版可使用动态表单企业版支持拖动表单及自定义的vue组件表单
1. 在【基础配置/流程设计】中添加一个流程模版,流程模版选择刚刚建的表单。建好流程模版,拥有该模版权限的用户就可以基于改模版创建流程实例了;
1. 在【流程中心/我的流程】中【新的申请】创建一个流程实例。创建成功后就可以在列表中看到该流程。流程节点对应的执行用户会在【流程中心/待处理流程】中看到该流程,选中需要审批的流程,点击【处理】按钮即可进行审批操作;
# 流程审批逻辑
当最终用户在【待处理流程】中审批一个流程实例时,流程实例会经过下面步骤进行处理:
@startuml
skinparam handwritten true
skinparam backgroundColor #EEEBDC
start
if (当前活动节点类型为会签) then (yes)
:标识当前节点状态;
:从所有的分支中找到一个用户可以审批的节点canCheckId;
if (没找到?) then (yes)
stop
endif
:标识canCheckId节点状态;
#HotPink:进行会签,结果为res;
if(res == TagState.No) then (yes)
:修改流程最终状态为不同意;
else if(res != string.Empty) then (yes)
stop
else (no)
:修改流程最终状态,修改活动节点,修改可执行人;
:添加扭转记录;
endif
else (no)
:标识当前节点状态;
if (同意) then (yes)
:修改流程最终状态,修改活动节点,修改可执行人;
:添加扭转记录;
else
:修改流程最终状态为不同意;
endif
:操作记录;
endif
stop
@enduml

View File

@@ -0,0 +1,123 @@
# 流程实例
流程实例指正在运行的一个流程。数据存放在FlowInstance表中该表核心字段如下
#### IsFinish流程的当前状态
- -1 草稿/召回:流程发起人主动撤销流程;【新增】
- 0 正在运行;
- 1 完成:流程结束,同时所有的审批都通过;
- 3 不同意:即流程结束,同时审批人员没有通过;
- 4 驳回:流程结束,可能发起的流程内容有问题,要求被驳回重新提交;
#### ActivityType当前节点的类型
- -1 无法运行,
- 0 会签开始,
- 1 会签结束,
- 2 一般节点,
- 3 开始节点,
- 4 流程运行结束
#### SchemeContent流程实例的具体内容
该字段存储的是一个JSON对象具体内容如下所示
```javascript
{
"title":"newFlow_1",
"nodes":[
{
"name":"node_1",
"left":75,
"top":90,
"type":"start round mix",
"id":1521797877921,
"width":26,
"height":26,
"alt":true
},
{
"name":"审核",
"left":235,
"top":97,
"type":"node",
"id":1521797879744,
"width":104,
"height":26,
"alt":true,
"setInfo":{
"NodeDesignateData":{
"users":[
"49df1602-f5f3-4d52-afb7-3802da619558",
"6ba79766-faa0-4259-8139-a4a6d35784e0"
],
"role":{
},
"org":{
}
},
"NodeCode":"FIRST",
"NodeName":"审核"
}
},
{
"name":"node_3",
"left":268,
"top":209,
"type":"end round",
"id":1521797881216,
"width":26,
"height":26,
"alt":true
}
],
"lines":[
{
"type":"sl",
"from":"1521797877921",
"to":"1521797879744",
"id":1521797883552,
"name":"",
"dash":false
},
{
"type":"sl",
"from":"1521797879744",
"to":"1521797881216",
"id":1521797884536,
"name":"",
"dash":false
}
],
"areas":{
},
"initNum":7
}
```
其中nodes为流程实例的所有节点。lines为流程实例的所有连线。节点的type属性为节点的类型属性对应上面提到的ActivityType
- -1无法运行
- 0会签开始即type为fork
- 1会签结束,即type为join
- 2一般节点,即type为node
- 3开始节点,即type为start
- 4流程运行结束即type为end

16
docs/core/form.md Normal file
View File

@@ -0,0 +1,16 @@
# 表单设计
OpenAuth.Net内置的表单类型有以下三种
## 动态表单
动态表单适用于灵活设计界面,逻辑简单的表单。这种表单无需编码,即可直接集成到流程功能。
## 自定义开发表单【企业版】
该类型表单需要开发者在源码中先编写好表单界面基于vue component,再提供给用户选择使用。适用于交互复杂的界面。详细请参考:[企业版工作流添加自定义表单](/pro/form.html)
## 可拖拽表单【企业版】
适用场景和普通的动态表单一样。但该表单操作方便,与系统界面风格匹配度高,缺点是排版没有普通的动态表单灵活,只能做简单的行排列。详细请参考:[可拖拽表单](/pro/dragform.html)

74
docs/core/identity.md Normal file
View File

@@ -0,0 +1,74 @@
# 登录认证及OAuth集成
OpenAuth.Net支持两种登录认证方式自定义token认证和基于IdentityServer的OAuth认证。
这两种方式通过配置webapi或mvc的appsettings.json可以自由切换:
```json
"IdentityServerUrl": "http://localhost:12796", //IdentityServer服务器地址。如果为空则不启用OAuth认证
```
1. 当IdentityServerUrl为空时采用普通的token认证这时不需要OpenAuth.Identity启动支持。
2. 当IdentityServerUrl配置了地址时则采用Identity认证方式。
## OpenAuth.Mvc OAuth认证
当启用了Identity时系统启动后界面如下
![MVC启用identity](/mvcidentity.png "mvcidentity")
这时点击登录超链接会跳转到OpenAuth.Identity登录界面。效果如下
![](/identity.png)
## OpenAuth.WebApi普通token认证
当IdentityServerUrl配置为空时采用普通的token认证客户端在访问的接口时先调用登录接口,得到授权token
![20220119182845](http://img.openauth.net.cn/20220119182845.png)
然后把获取到的token值添加到http header的X-Token中,即可调用对应的API接口。
![20220119182853](http://img.openauth.net.cn/20220119182853.png)
## OpenAuth.WebApi OAuth
当启用了Identity时客户端调用API需要先通过OpenAuth.IdentityServer服务器的OAuth验证才能调用接口。OpenAuth.Net调用API的客户端有两种
#### SwaggerUI
当我们启动了OpenAuth.WebApi在浏览器打开[http://localhost:52789/swagger/index.html](http://localhost:52789/swagger/index.html)时其实是Swagger框架给我们生成的一个调动客户端对于启用了Identity的服务Swagger会有一个Authorise的操作按钮
![20220119180445](http://img.openauth.net.cn/20220119180445.png)
![20220119180503](http://img.openauth.net.cn/20220119180503.png)
点击登录超链接会跳转到OpenAuth.Identity登录界面。登录成功后会自动跳转回来。提示授权成功
![20220119180546](http://img.openauth.net.cn/20220119180546.png)
这时所有的接口都可以直接访问访问时会在http头上自动加认证信息
![20220119180608](http://img.openauth.net.cn/20220119180608.png)
#### OpenAuth.Pro
在使用企业版vue界面访问OpenAuth.WebApi时已经在文件`.env.dev`中配置好相关选项,可以直接使用,无需其他处理。
```python
VUE_APP_OIDC_AUTHORITY = http://localhost:12796 #Identity服务器地址
VUE_APP_OIDC_CLIENTID = OpenAuth.Pro #客户端名称
VUE_APP_OIDC_REDIRECTURI = http://localhost:1803/#/oidc-callback #登录回调
VUE_APP_OIDC_POSTLOGOUTREDIRECTURI = http://localhost:1803 #退出登录回调
VUE_APP_OIDC_RESPONSETYPE = code #认证方式
VUE_APP_OIDC_SCOPE = openid profile openauthapi #认证范围
VUE_APP_OIDC_AUTOMATICSILENTRENEW = true
VUE_APP_OIDC_SILENTREDIRECTURI = http://localhost:1803/silent-renew-oidc.html
```

48
docs/core/job.md Normal file
View File

@@ -0,0 +1,48 @@
# 定时任务
::: tip 提示
定时任务基于Quartz.Net开发
:::
## 编写任务代码
在OpenAuth.App中编写定时任务的执行代码。比如`TestJob`
```csharp
namespace OpenAuth.App.Jobs
{
public class TestJob : IJob
{
private OpenJobApp _openJobApp;
public TestJob(OpenJobApp openJobApp)
{
_openJobApp = openJobApp;
}
public Task Execute(IJobExecutionContext context)
{
var jobId = context.MergedJobDataMap.GetString(Define.JOBMAPKEY);
//todo:获取到定时任务的id可以可以加入自己的自动任务逻辑
_openJobApp.RecordRun(jobId);
return Task.Delay(1);
}
}
}
```
## 添加任务执行规则
编写完任务的执行代码后即可运行系统,在界面【基础配置】-【定时任务】中添加任务的执行规则,如图:
![](/addjob.png)
添加任务规则后,在界面直接点击`启用`即可
::: tip 提示
企业版提供可视化的CRON编辑界面,如图:
![](/addjobpro.png)
:::

120
docs/core/log.md Normal file
View File

@@ -0,0 +1,120 @@
# 日志操作
## 普通日志
框架默认使用Log4Net作为记录日志的方式可以在Program.cs中配置日志参数或调整为其他日志。日志默认按日期生成日志文件并存放在`log\`目录下。简单用法如下:
```csharp
//具体代码参考OpenAuth.App/OpenJobApp.cs此处简化真实逻辑方便理解
public void RecordRun(string jobId)
{
//其他代码略
_logger.LogInformation($"运行了自动任务:{job.JobName}");
}
public OpenJobApp(IUnitWork unitWork, IRepository<OpenJob> repository,
IAuth auth, ILogger<OpenJobApp> logger) : base(unitWork, repository, auth)
{
_logger = logger;
}
```
## 数据库日志
如果想使用数据库记录业务日志(如系统默认的用户操作日志等),可以使用`SysLogApp`模块功能。日志可以在站点【消息日志】->【系统日志】中查看到记录的日志信息。简单用法如下:
```csharp
//具体代码参考OpenAuth.App/OpenJobApp.cs此处简化真实逻辑方便理解
public void RecordRun(string jobId)
{
//其他代码略
_sysLogApp.Add(new SysLog
{
CreateName = "Quartz",
CreateId = "Quartz",
TypeName = "定时任务",
TypeId = "AUTOJOB",
Content = $"运行了自动任务:{job.JobName}"
});
}
public OpenJobApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<OpenJob,OpenAuthDBContext> repository,
IAuth auth, SysLogApp sysLogApp) : base(unitWork, repository, auth)
{
_sysLogApp = sysLogApp;
}
```
## EF打印Sql日志
在调试数据库时需要打印真正执行的SQL信息。最简单的方式是使用下面方法输出到控制台
```csharp
public partial class OpenAuthDBContext : DbContext
{
public static readonly ILoggerFactory MyLoggerFactory
= LoggerFactory.Create(builder => { builder.AddConsole(); });
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableSensitiveDataLogging (true); //允许打印参数
optionsBuilder.UseLoggerFactory (MyLoggerFactory);
base.OnConfiguring (optionsBuilder);
}
}
```
## EF输出Sql到log4net
框架目前直接配置`appsettings.Development.json`即可完成输出sql语句到log4net对应的日志文件中。如下
```
"Logging": {
"LogLevel": {
"Microsoft.EntityFrameworkCore.Database.Command": "Information" //EF输出SQL语句
}
}
```
正式发布环境下,如无特殊需求,建议在`appsettings.Production.json`配置中关闭该输出
## 在Swagger中输出日志
框架集成mini profiler工具在swagger中或其他客户端调用WebApi接口时可以直接在swagger中显示日志信息需要刷新。如下图
![](/miniprofiler1.png)
点击`sql`列的时间查看详细的sql执行情况
![](/miniprofiler2.png)
如果需要订制日志信息,查看更详细的日志情况,可以自己调整代码实现。以登录接口为例,添加以下代码:
```csharp
[HttpPost]
[AllowAnonymous]
public LoginResult Login(PassportLoginRequest request)
{
var result = new LoginResult();
using (MiniProfiler.Current.Step("步骤一"))
{
result = _authUtil.Login(request.AppKey, request.Account, request.Password);
}
using (MiniProfiler.Current.Step("步骤二"))
{
//代码略
}
using (MiniProfiler.Current.Step("步骤三"))
{
//代码略
}
return result;
}
```
这时调用该API后即可看到具体步骤一、步骤二、步骤三的执行时间情况了

29
docs/core/logininfo.md Normal file
View File

@@ -0,0 +1,29 @@
# 登录信息
框架在应用层任意业务逻辑中,均可以通过`IAuth`接口判断是否登录和获取登录信息。所有继承BaseApp的业务逻辑可以直接使用`_auth`成员变量直接获取登录用户信息。
```csharp
public class RoleApp : BaseApp<Role,OpenAuthDBContext>
{
/// <summary>
/// 加载当前登录用户可访问的全部角色
/// </summary>
public List<Role> Load(QueryRoleListReq request)
{
var loginUser = _auth.GetCurrentUser();
if (loginUser == null)
{
throw new CommonException("登录已过期", Define.INVALID_TOKEN);
}
//其他代码略
}
public RoleApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Role,OpenAuthDBContext> repository,IAuth auth) : base(unitWork, repository, auth)
{
}
}
```

98
docs/core/multidbs.md Normal file
View File

@@ -0,0 +1,98 @@
# 配置多数据库
框架支持同时访问多个数据库。具体操作如下:
## 添加新数据库连接字符串
在配置文件appsettings.json中添加新的连接字符串`OpenAuthDBContext2`
```csharp
"ConnectionStrings": {
"OpenAuthDBContext": "Data Source=.;Initial Catalog=OpenAuthPro;User=sa;Password=000000",
"OpenAuthDBContext2": "Data Source=.;Initial Catalog=OpenAuthDB;User=sa;Password=000000"
}
"AppSetting": {
"DbTypes": {
"OpenAuthDBContext":"SqlServer" //数据库类型SqlServer、MySql、Oracle
,"OpenAuthDBContext2":"SqlServer" //链接字符串OpenAuthDBContext2对应的数据库类型
}
}
```
## 添加新的数据上下文
在OpenAuth.Repository中添加新的数据库上下文比如`OpenAuthDBContext2`
```csharp
public class OpenAuthDBContext2 : DbContext
{
private IConfiguration _configuration;
private ILoggerFactory _LoggerFactory;
private const string _connectstr = "OpenAuthDBContext2";
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLoggerFactory (_LoggerFactory);
string connect = _configuration.GetConnectionString(_connectstr);
if (string.IsNullOrEmpty(connect))
{
throw new Exception($"未能找到{_connectstr}对应的连接字符串信息");
}
//这个地方如果用IOption在单元测试的时候会获取不到AppSetting的值😅
var dbtypes = _configuration.GetSection("AppSetting:DbTypes").GetChildren()
.ToDictionary(x => x.Key, x => x.Value);
var dbType = dbtypes[_connectstr];
if (dbType == Define.DBTYPE_SQLSERVER)
{
optionsBuilder.UseSqlServer(connect);
}
else if(dbType == Define.DBTYPE_MYSQL) //mysql
{
optionsBuilder.UseMySql(connect);
}
else
{
optionsBuilder.UseOracle(connect);
}
base.OnConfiguring (optionsBuilder);
}
public OpenAuthDBContext2(DbContextOptions<OpenAuthDBContext2> options,
ILoggerFactory loggerFactory,IConfiguration configuration)
: base(options)
{
_LoggerFactory = loggerFactory;
_configuration = configuration;
}
... //其他代码请参考OpenAuthDbContext
}
```
## 注入新数据库
在项目OpenAuth.WebApi等的启动代码`Startup.cs`中,注入刚刚添加的数据库
```csharp
services.AddDbContext<OpenAuthDBContext2>();
```
## 编写业务代码
我们以系统日志模块为例,只需要调整以下代码,然后运行就可以发现,日志已经全部记录到新的数据库中。
```csharp
public class SysLogApp : BaseApp<SysLog,OpenAuthDBContext2>
{
public SysLogApp(IUnitWork<OpenAuthDBContext2> unitWork, IRepository<SysLog,OpenAuthDBContext2> repository) : base(unitWork, repository, null)
{
}
...//剩余的代码和系统自带的模块完全一致
}
```

80
docs/core/multitenant.md Normal file
View File

@@ -0,0 +1,80 @@
# 多租户
目前市面上主流的多租户方案有三种:
1. **独立数据库** 即为不同的租户提供独立的数据库。
1. **共享数据库独立Schema** 即多个或所有租户共享一个数据库实例但是每个租户一个Schema也可叫做一个user。底层库比如是DB2、ORACLE等一个数据库下可以有多个SCHEMA。
1. **共享数据库共享Schema共享数据表** 即租户共享同一个数据库实例、同一个Schema但在表中增加TenantID多租户的数据字段在程序逻辑上进行区分。
为了兼容以前的版本OpenAuth采用的是第一种方式即为每个租户建一个新的数据库然后通过客户端请求的租户IdtenantId来分离数据。
## 如何增加一个新租户?
#### 后端添加
后端添加新租户连接字符串即可:
```javascript
"ConnectionStrings": {
"new_tenantid": "server=127.0.0.1;user id=root;database=openauthpro;password=000000" //新租户id对应的连接字符串
},
```
::: warning 注意
这里为了方便理解租户id用的是`new_tenantid`,真实环境里最好用类似UUID风格的无意义id
:::
#### 前端添加
比如在vue element-ui中,在登录时增加选择租户列表:
```html
<el-select v-model="tenant" placeholder="请选择" @change="tenantChange">
<el-option
v-for="item in tenants"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
export default {
name: 'login',
data() {
return {
tenant: this.tenantid || 'OpenAuthDBContext', //当前选择的租户
tenants:[{
value: 'OpenAuthDBContext',
label: '默认租户'
},{ //添加的新租户
value: 'new_tenantid',
label: '新租户'
}]
}
}
}
```
前端在所有http请求的时候在请求头中增加`tenantId`信息,保证每次请求带上租户信息。比如用axios请求时
```javascript
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // api的base_url
timeout: 50000 // 请求超时时间
})
// request拦截器
service.interceptors.request.use(config => {
config.headers['tenantId'] = store.getters.tenantid
//其他代码略...
})
```

217
docs/core/routineupdate.md Normal file
View File

@@ -0,0 +1,217 @@
# 日常提交(针对dev分支)
* 2022.12.22 退出登录时清空tag标签;
* 2022.12.20 修复多个模块名称相同时只能打开一个的BUG;
* 2022.12.17 fix 流程发起页面切换vform不能正常执行onCreated脚本;
* 2022.12.15 升级vform到2.3.6;
* 2022.11.26 修复[事务中使用异步方式后报错](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I63AOC);
* 2022.11.18 修复[拖拽表单不能关联数据库](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I61V1D);
* 2022.10.05 完成vue3多表代码生成器模版;
* 2022.10.01 增加vue3多表代码生成器模版;
* 2022.09.21 完成vue3 setup模式单表代码生成;
* 2022.09.15 增加vue3代码生成器模版完成单表动态头部生成;
* 2022.09.12 代码生成器增加vue3参数;
* 2022.08.15 修复选择租户;
* 2022.08.14 修复左侧导航栏异常;
* 2022.08.13 完成vue3版本流程设计、流程处理及展示;
* 2022.08.03 完成vue3版本流程图工具、画布处理;
* 2022.07.26 完成vue3 jsplumb引入;
* 2022.06.14 完成vue3版本表单设计器;
* 2022.06.12 完成vue2版本表单设计器;
* 2022.05.12 初始化vue3+vite版本;
* 2022.01.19 增加对sql只返回string的支持;
* 2022.01.17 修复添加表单时如果关联的数据库已存在的bug
* 2022.01.15 增加拖动表单生成数据库表
* 2022.01.03 增加plantuml支持
* 2022.01.01 增加API部署说明
* 2021.12.28 增加工作流添加自定义表单
* 2021.12.10 修复非动态头部生成vue界面时异常
* 2021.12.08 主从表以ParentId为准而不是DetailTable
* 2021.12.07 sqlserver float类型对应C# double类型
* 2021.11.30 修复子表加载失败的问题
* 2021.11.14 修复代码生成器
* 2021.11.04 简化代码
* 2021.10.18 采用代码生成器的表结构控制前端显示
* 2021.10.03 升级EF及所有三方的版本
* 2021.09.22 fix issue [OpenAuth.Pro前端可编辑数量为单数时只显示单数减一的字段数](https://gitee.com/yubaolee/OpenAuth.Core/issues/I4BBIG)
* 2021.09.11 发布3.3版;
* 2021.09.08 fix issue [删除角色后用户还有角色模块访问权限](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I494N1)
* 2021.09.05 完成主从表生成;
* 2021.09.02 完成单个表格vue的生成
* 2021.08.31 使用全新的头部渲染;
* 2021.08.23 可以动态控制复杂界面显示编辑权限,采用代码生成的表定义来控制;
* 2021.07.09 流程审批时增加可编辑表单处理;
* 2021.07.02 fix issue 兼容oracle 11g
* 2021.06.22 系统消息按时间倒序排列;
* 2021.06.18 使用雪花算法做Id时出现异常
* 2021.06.15 修复加载消息列表异常;
* 2021.06.13 增加系统消息;
* 2021.06.02 删除已过期文件,优化注释;
* 2021.05.26 流程处理增加消息通知;
* 2021.05.24 集成miniprofiler可以监控API运行情况。[查看使用说明](http://doc.openauth.net.cn/core/log.html#%E5%9C%A8swagger%E4%B8%AD%E8%BE%93%E5%87%BA%E6%97%A5%E5%BF%97 )
* 2021.05.23 [模块管理页面加载时默认显示第一条](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3RUOR)
* 2021.05.21 新增编辑流程功能(草稿和驳回状态);
* 2021.05.17 [增加配置启动端口](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3QUV1)
* 2021.05.14 调整样式添加刷新页面tag标签保留功能
* 2021.05.12 [修复拖动表单上传异常](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3QN22)
* 2021.05.09 增加自定义模态验证异常返回信息;
* 2021.05.08 合并PR[增加API访问审计;禁用.net自动模态验证,采用系统全局异常捕获机制](https://gitee.com/dotnetchina/OpenAuth.Net/pulls/12)
* 2021.05.07 swagger增加分组的功能
* 2021.05.06 fix issue [会签节点异常,提示'-1' was not present in the dictionary](https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3PE3R)
* 2021.05.01 fix issue [CodeSmith生成的后端代码报错](https://gitee.com/yubaolee/OpenAuth.Core/issues/I3OXJZ)
* 2021.04.28 增加站点启动时自动运行状态为【正在运行】的定时任务;
* 2021.04.27 增加存储过程调用的支持;
* 2021.04.26 fix issue [生成的更新字段不包含默认的CreateUser等](https://gitee.com/yubaolee/OpenAuth.Core/issues/I3O5S3)
* 2021.04.25 增加流程执行时可以选择用户或角色(而不是设计时选择);
* 2021.04.21 不同的租户,可以连不同类型数据库;
* 2021.04.16 增加Oracle驱动支持
* 2021.04.15 调整项目文件结构,代码生成器按新的结构生成;
* 2021.04.14 增加流程启动、撤销功能;
* 2021.04.13 增加新的流程状态-草稿;
* 2021.04.01 优化代码生成器,可以根据主键类型自动匹配父类;
* 2021.03.29 优化雪花算法;
* 2021.03.22 全面删除svg图标使用iconfont并增加图标选择
* 2021.03.18 fix https://gitee.com/dotnetchina/OpenAuth.Net/issues/I3BUF5
* 2021.03.17 驳回状态可以在待处理列表中展示并处理;
* 2021.03.13 增加雪花算法支持、增加自动增长型Id的支持
* 2021.03.09 增加redis缓存支持
* 2021.03.03 代码生成器加上删除时添加弹出提醒的代码;
* 2021.03.02 修复流程分支判定;
* 2021.03.01 修复流程分支不能判断字符串的问题;
* 2021.02.20 新增三级菜单名称前Icon小图标
* 2021.02.18 增加三级菜单支持
* 2021.01.17 调整非法租户逻辑;
* 2021.01.14 fix issue [#I2D0CX](https://gitee.com/yubaolee/OpenAuth.Core/issues/I2D0CX)
* 2021.01.10 完成对多租户的支持;
* 2021.01.06 fix issue [#I2C4K0](https://gitee.com/yubaolee/OpenAuth.Core/issues/I2C4K0)
* 2021.01.03 启动时显示连接字符串;
* 2020.12.28 新增多数据源;
* 2020.12.27 优化EF输出SQL语句
* 2020.12.26 对同时多个HTTP修改请求进行加锁处理
* 2020.12.21 增加附件管理;
* 2020.12.19 上传图片支持生成缩略图;
* 2020.12.17 增加异步测试、事务测试;
* 2020.12.16 完成UnitWork异步化
* 2020.12.11 Repository增加异步读写接口
* 2020.12.09 fix issue [#I1RFOQ](https://gitee.com/yubaolee/OpenAuth.Core/issues/I1RFOQ)
* 2020.12.02 所有数据加载调整为异步模式;
* 2020.11.15 修复layui选择组织机构时数据回写的BUG
* 2020.11.03 修复layui icon选择BUG
* 2020.10.20 修复代码生成器mysql创建主键字段
* 2020.10.13 调整代码生成器生成vue views的路径调整为小写
* 2020.09.23 发布企业版代码生成器功能;
* 2020.09.10 完成所有后端生成实体、生成业务功能、生成API
* 2020.08.12 完成代码生成器--自动创建WebApi Controller功能的开发
* 2020.08.10 完成代码生成器--自动创建实体功能的开发;
* 2020.08.06 增加代码生成器创建接口,为在线代码生成器做准备;
* 2020.08.04 修复企业版字典分类页面样式异常;增加获取数据库结构接口;
* 2020.08.01 获取实体属性时,按小写判断实体是否存在。修复:[I1PN8N](https://gitee.com/yubaolee/OpenAuth.Core/issues/I1PN8N) [I1PN5O](https://gitee.com/yubaolee/OpenAuth.Core/issues/I1PN5O) [I1PMYX](https://gitee.com/yubaolee/OpenAuth.Core/issues/I1PMYX)

32
docs/core/specialist.md Normal file
View File

@@ -0,0 +1,32 @@
# 开发规范
## 新增数据库名称规范
子系统名称+业务名称+表尾,其中表尾名称规则如下:
- 基础主数据以Mst结尾
- 普通业务表以Tbl结尾
- 业务明细表以Dtbl结尾
比如:
- WMS系统客户主数据表WmsCustomerMst
- WMS系统入库订单头表WmsInboundOrderTbl
- WMS系统入库订单明细表WmsInboundOrderDtbl
## 数据库字段类型
主键id统一使用Domain:PrimaryKey针对SqlServer数据库非Sql Server根据需要定义
状态类,标识类的字段统一使用bit not null
表示分类的字段统一使用PrimaryKey。数值从Category中获取。

175
docs/core/start.md Normal file
View File

@@ -0,0 +1,175 @@
# 快速开始
## 下载代码
gitee上面两个版本仅SDK的版本不同代码完全相同。其中
* [OpenAuth.Net](https://gitee.com/dotnetchina/OpenAuth.Net) 的SDK版本为5.0.100,推荐使用该版本
* [OpenAuth.Core](https://gitee.com/yubaolee/OpenAuth.Core) 的SDK版本为.Net Core 3.1.100,历史原因暂且保留,未来的某天会关闭它
.Net目前SDK升级特别方便只需花费3分钟时间既可升级到.Net 6/7/8...等。请参考:[3分钟的时间把.net core 3.1的升级到.NET 5](https://www.cnblogs.com/yubaolee/p/Net3ToNet5.html)所以不要纠结SDK版本问题。
## 安装sdk
下载安装微软官方SDK代码地址https://dotnet.microsoft.com/download
## 项目结构
OpenAuth.Net文件夹结构及功能说明如下
```
📦OpenAuth.Net
┣ 📂CodeSmith
┃ ┗ 📂CSharp
┃ ┃ ┗ 📜WebGenerate.cst //生成Web页面
┣ 📂Infrastructure //基础工具类
┣ 📂mysql初始化脚本
┣ 📂OpenAuth.App //应用逻辑代码
┣ 📂OpenAuth.Identity //IdentityServer4服务器提供OAuth服务
┣ 📂OpenAuth.Mvc //开源版Web站点
┣ 📂OpenAuth.Repository //数据库访问相关代码
┣ 📂OpenAuth.WebApi //WebApi接口站点
┣ 📂sql server 初始化脚本
┣ 📜.gitattributes
┣ 📜.gitignore
┣ 📜LICENSE
┣ 📜OpenAuth.Core.sln //解决方案
┗ 📜README.md
```
其中调用关系为:
@startuml
hide footbox
skinparam handwritten true
actor 用户
boundary index.cshtml
control XXController
entity OpenAuth.App
entity OpenAuth.Repository
database OpenAuthDB
box "OpenAuth.Mvc" #LightBlue
participant index.cshtml
participant XXController
end box
participant OpenAuth.App
participant OpenAuth.Repository
participant OpenAuthDB
用户 -> index.cshtml : 用户浏览页面
index.cshtml -> XXController : 前端通过ajax调用数据
XXController -> OpenAuth.App : 调用逻辑层
OpenAuth.App -> OpenAuth.Repository : 逻辑层调用仓储进行数据读写
OpenAuth.Repository -> OpenAuthDB : 仓储层进行数据库操作
@enduml
我们以【资源管理】功能为例,该功能涉及的文件如下:
![20220407153729](http://img.openauth.net.cn/20220407153729.png)
## 初始化数据库
使用数据库脚本`sql server 初始化脚本``mysql初始化脚本` 文件夹里面的结构脚本和数据脚本初始化数据库
::: warning 注意
如果使用企业版的OpenAuth.WebApi,则新建一个空数据库OpenAuthPro。使用OpenAuth.Pro前端源码文件夹【sql脚本】中运行`Sql Server脚本.sql`或mysql脚本
:::
## 打开项目
使用Visual Studio 2019或Rider打开 `OpenAuth.Core.sln`
::: tip 提示
v2.0及以后版本因使用.net core 3.1必须使用visual Studio 2019及以上版本打开
v2.0以前的版本可以使用visual Studio 2017
如果开发使用的电脑安装有多个版本的SDK如同时有.net core 3.1 和.net 5可以在根目录新建一个`global.json`文件来指定.net版本文件内容如下
```
{
"sdk": {
"version": "3.1.100"
}
}
```
:::
## 修改配置
`ASP.NET Core` 应用程序启动时默认加载`appsettings.json`作为应用配置。同时还支持不同的运行环境加载对应的配置文件,如:
- 开发环境Development对应 `appsettings.Development.json`
- 部署环境Production对应 `appsettings.Production.json`
::: tip 提示
- 很多用户部署后提示连接数据库失败,很大原因就是没有修改`appsettings.Production.json`里面连接字符串
- 有些用户找不到`appsettings.Production.json`在哪visual studio中点击`appsettings.json`左边的三角标识即可看到
:::
#### 修改单数据库连接字符串
* 修改OpenAuth.Mvc/appsettings.json连接字符串如下
```json
"ConnectionStrings": {
"OpenAuthDBContext": "Data Source=.;Initial Catalog=OpenAuthPro;User=sa;Password=000000"
},
"AppSetting": {
"DbTypes": {
"OpenAuthDBContext":"SqlServer" //数据库类型SqlServer、MySql、Oracle
}
```
#### 修改多数据库连接字符串
```json
"ConnectionStrings": {
"OpenAuthDBContext": "Data Source=.;Initial Catalog=OpenAuthPro;User=sa;Password=000000"
"OpenAuthDBContext2": "DATA SOURCE=192.168.0.118:1521/YUBAO;PASSWORD=000000;Validate Connection=true;PERSIST SECURITY INFO=True;USER ID=yubaolee;" //racle
"OpenAuthDBContext3": "server=127.0.0.1;user id=root;database=openauthpro;password=000000" //my sql
},
"AppSetting": {
"DbTypes": {
"OpenAuthDBContext":"SqlServer" //数据库类型SqlServer、MySql、Oracle
,"OpenAuthDBContext2":"Oracle"
,"OpenAuthDBContext3":"MySql"
},
```
## 编译运行MVC
使用visualstudio生成解决方案。
`注首次启动时visual studio会启动nuget还原第三方依赖包请保持网络通畅并等待一段时间`
启动openauth.mvc项目。
![启动](/startmvc.png "启动")
启动成功后使用浏览器打开[http://localhost:1802](http://localhost:1802) 即可访问,如下图所示:
![说明](/mvcmain.png "说明")
## 编译运行WebApi
使用visualstudio生成解决方案。
`注首次启动时visual studio会启动nuget还原第三方依赖包请保持网络通畅并等待一段时间`
启动openauth.webapi项目。
![20220102000528](http://img.openauth.net.cn/20220102000528.png)
启动成功后使用浏览器打开[http://localhost:52789/swagger/index.html](http://localhost:52789/swagger/index.html) 即可访问,如下图所示:
![20220101233542](http://img.openauth.net.cn/20220101233542.png)

37
docs/core/thirdparty.md Normal file
View File

@@ -0,0 +1,37 @@
# 三方对接
* 在OpenAuth中设计表单注意表单中的控件名称在步骤3调用OpenAuth创建流程实例接口时frmData参数中的属性必须严格按该命名提交。
![](/formthirdparty.png "表单设计说明")
* 在OpenAuth中设计流程制定相关的工作流程并在每个流程节点配置回调URL路径如下
![](/flowthirdparty.png "三方URL设置")
* 三方已有系统界面提交表单时调用创建流程实例接口http://localhost:52789/api/FlowInstances/Add在OpenAuth中创建一条新的流程实例 接口参数如下:
```javascript
{
schemeId:'cdd8191e-6a99-4d66-aac0-fae52c0f2232', //流程模板中已存在的模板ID
schemeCode:'', //与流程模板ID二者选一个即可
frmData:'{\"TOOLS\":\"电脑\",\"NUMBERS\":\"1\"}', //严格按照第一步中表单规则
code:'1563811467051',
customName:'三方创建的新物品领用',
}
```
* 用户正常在OpenAuth中执行流程如果当前节点设置了回调URL的节点OpenAuth会采用WebAPI POST方式回调回调时具体参数如下
```javascript
{
flowInstanceId:"0ceff0f8-f848-440c-bc26-d8605ac858cd", //流程实例ID
nodeName: "admin审批", //节点名称
nodeId: "15333321", //节点ID
userId: "0ceff0f8-f848-440c-bc26-d8605ac858cd",
userName: "admin", //审核人账号
result: 1, //审核结果 1通过;2不通过3驳回
description: "做的不错", //审核描述
execTime: "2019-07-07 12:00:00", //审核时间
isFinish: true //是否结束
}
```

72
docs/core/unittest.md Normal file
View File

@@ -0,0 +1,72 @@
# 单元测试
为了方便项目调试框架的所有层均支持单元测试。代码基于NUnit框架编写。测试内如大概如下
* OpenAuth.Reposiroty: 直接测试数据库是否可以正常读写测试级别DbContext。在该项目的`TestBase.cs`中配置连接字符串;
* OpenAuth.App: 测试所有业务逻辑测试级别为各种xxxApp/xxxService等。可以模拟用户登录和前端Cookie提交的信息。在该项目的`TestBase.cs`中配置连接字符串;
* OpenAuth.Mvc: 测试MVC的访问可以模拟用户登录和前端Cookie提交的信息。使用OpenAuth.App中的测试连接字符串
* OpenAuth.WebApi: 测试接口WebApi访问可以模拟用户登录和前端Cookie提交的信息。使用OpenAuth.App中的测试连接字符串
所有的测试代码均在每个项目的`Test`文件夹中编写。比如`OpenAuth.App\Test\TestAccessObjs.cs`
```csharp
/// <summary>
/// 测试为部门分配用户
/// </summary>
[Test]
public void AssignOrgUsers()
{
var app = _autofacServiceProvider.GetService<RevelanceManagerApp>();
var userApp = _autofacServiceProvider.GetService<UserManagerApp>();
app.AssignOrgUsers(new AssignOrgUsers
{
OrgId = "8e31553c-cab8-4eb3-90b5-5f8ff1d21801",
UserIds = new []{"96f63f9d-e8c8-4258-963e-3327ed7d6f56"}
});
//获取机构的所有用户
var result = userApp.Load(new QueryUserListReq
{
orgId = "8e31553c-cab8-4eb3-90b5-5f8ff1d21801",
page = 1,
limit = 10
});
Console.WriteLine(JsonHelper.Instance.Serialize(result));
}
```
::: warning 注意
每个单元测试类都会继承`TestBase`,该类有一个虚函数`GetService`默认只注入了缓存Cache配置Option。如果在测试的过程中需要模拟登录用户cookie等信息需要在测试类中重写该方法。比如一个典型的重写如下
```csharp
public override ServiceCollection GetService()
{
var services = new ServiceCollection();
//模拟帐号test3记录在缓存中并与tokentest关联
var cachemock = new Mock<ICacheContext>();
cachemock.Setup(x => x.Get<UserAuthSession>("tokentest")).Returns(new UserAuthSession { Account = "test3" });
services.AddScoped(x => cachemock.Object);
//模拟客户端请求的token值为`tokentest`
var httpContextAccessorMock = new Mock<IHttpContextAccessor>();
httpContextAccessorMock.Setup(x => x.HttpContext.Request.Query[Define.TOKEN_NAME]).Returns("tokentest");
services.AddScoped(x => httpContextAccessorMock.Object);
//模拟httpclientfactory
var mockHttpFac = new Mock<IHttpClientFactory>();
services.AddScoped(x => mockHttpFac.Object);
return services;
}
```
:::

280
docs/core/unitwork.md Normal file
View File

@@ -0,0 +1,280 @@
# 数据库读写及事务处理
OpenAuth.Core使用Repository和Unitwork两种方式访问数据库。
## 使用场景
Repository适用于单表操作没有事务需求的场景
Unitwork适用于多表操作尤其是更新操作有事务需求的场景
::: tip 什么是UnitWork
在web应用中由于每个用户的请求都是属于不同线程的需要保持每次请求的所有数据操作都成功的情况下提交数据只要有一个失败的操作则会对用户的此次请求的所有操作进行回滚以确保用户操作的数据始终处于有效的状态。其实就两个字**事务**
:::
## 单表操作Repository
假设数据库有一个表名称为Stock。则在OpenAuth.App中编写业务代码。比如`StockApp`
```csharp
namespace OpenAuth.App
{
public class StockApp : BaseApp<Stock,OpenAuthDBContext>
{
/// <summary>
/// 加载列表
/// </summary>
public TableData Load(QueryStockListReq request)
{
var result = new TableData();
var objs = Repository.Find(null);
if (!string.IsNullOrEmpty(request.key))
{
objs = objs.Where(u => u.Id.Contains(request.key));
}
result.data = objs.OrderBy(u => u.Id)
.Skip((request.page - 1) * request.limit)
.Take(request.limit);
result.count = objs.Count();
return result;
}
public void Add(AddOrUpdateStockReq req)
{
var obj = req.MapTo<Stock>();
//todo:补充或调整自己需要的字段
obj.CreateTime = DateTime.Now;
Repository.Add(obj);
}
public void Update(AddOrUpdateStockReq obj)
{
Repository.Update(u => u.Id == obj.Id, u => new Stock
{
//todo:补充或调整自己需要的字段
});
}
public StockApp(IUnitWork<OpenAuthDBContext> unitWork, IRepository<Stock,OpenAuthDBContext> repository,IAuth auth) : base(unitWork, repository,auth)
{
}
}
}
```
## 事务操作UnitWork
默认情况下EF每执行一次SaveChanges()方法时就会新建一个事务然后将context中的CUD操作都在这个事务中进行。使用方式如下
```csharp
public void Update(AddOrUpdateStockReq obj)
{
UnitWork.Add<SysLog>(new SysLog
{
//todo:模拟新增操作
});
var stock = UnitWork.FirstOrDefault<Stock>(u => u.Id == obj.Id);
stock.Name = "xxxx";
UnitWork.Update(stock); //更新操作
var other = UnitWork.FirstOrDefault<OtherTable>(u => u.Id == obj.Id);
other.Name = "xxxx";
UnitWork.Update(other); //其他更新操作
UnitWork.Save(); //只有一次Save()操作
}
```
如果在一个事务里面有多次`SaveChanges()`的情况需要使用OpenAuth.Core提供的`ExecuteWithTransaction`处理。如下:
```csharp
//代码详见TestTransaction.cs/NormalSubmit()
UnitWork.ExecuteWithTransaction(() =>
{
var account = "user_" + DateTime.Now.ToString("yyyy_MM_dd HH:mm:ss");
var user = new User
{
Id = account,
Account = account,
Name = account,
};
unitWork.Add(user);
unitWork.Save(); //第一次savechanges()
user.Account = "Trans_" + user.Account;
unitWork.Update(user);
unitWork.Save(); //第二次savechanges()
//Z.EntityFramework.Plus的Update内部自动调用了SaveChanges(),算第三次
unitWork.Update<User>(u => u.Id == account, u => new User
{
Account = "Trans2_" + user.Account
});
});
```
或者异步方式:
```csharp
public async Task AddUserAndLogAsync()
{
await UnitWork.ExecuteWithTransactionAsync(async () =>
{
var account = await AddUserAsync();
UnitWork.Add(new SysLog()
{
Content = $"新增了用户{account}",
Id = account
});
UnitWork.Save();
});
}
private async Task<string> AddUserAsync()
{
var account = "user_" + DateTime.Now.ToString("yyyy_MM_dd HH:mm:ss");
var user = new User
{
Account = account,
Name = account
};
await Repository.AddAsync(user);
return account;
}
```
发生这种情况,通常是因为在各个应用层逻辑内部已经调用了`UnitWrok.Save()`,比如:
```csharp
//详细代码请查看UserManagerApp.cs,本例简化真实逻辑,方便理解
private RevelanceManagerApp _revelanceApp;
public void AddOrUpdate(UpdateUserReq request)
{
UnitWork.ExecuteWithTransaction(() =>
{
User requser = request;
requser.CreateTime = DateTime.Now;
UnitWork.Add(requser);
UnitWork.Save();
string[] orgIds = request.OrganizationIds.Split(',').ToArray();
//下面两个方法各自内部都会调用UnitWork.Save()
_revelanceApp.DeleteBy(Define.USERORG, requser.Id);
_revelanceApp.Assign(Define.USERORG, orgIds.ToLookup(u => requser.Id));
});
}
```
## 多表查询
简单的多表查询可以使用UnitWork完成。例如
```csharp
/// <summary>
/// 加载用户的部门
/// </summary>
public List<Org> LoadForUser(string userId)
{
var result = from userorg in UnitWork.Find<Relevance>(null)
join org in UnitWork.Find<Org>(null) on userorg.SecondId equals org.Id
where userorg.FirstId == userId && userorg.Key == Define.USERORG
select org;
return result.ToList();
}
```
如果是复杂的SQL查询建议使用下面的SQL语句查询以获得更高的性能。
## SQL 语句查询
框架提供两个SQL语句查询的接口:
* FromSql: 返回数据库表对应的实体必需在在DbContext中增加对应的DbSset
::: tip 提示
EF Core 3.x版本或以前如果返回数据库中不存在的实体必需在在DbContext中增加DbQuery<实体>并且使用dbcontext.Query<XXX>("select * from xx")进行查询。EF Core 5.0以后已经全部统一为DbSet并使用FromSql进行查询
:::
### 返回数据库表
```csharp
//UserManagerApp.cs
var users = UnitWork.FromSql<User>("select * from user");
```
### 返回非数据库表
```csharp
//OpenAuthDBContext中添加访问
public virtual DbSet<UserResp> UserResps { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
modelBuilder.Entity<UserResp>().HasNoKey();
}
//使用
var users = UnitWork.FromSql<UserResp>("select * from user");
```
## 执行存储过程
#### Sql Server
UnitWork提供执行存储过程接口`ExecProcedure`,使用如下:
``` csharp
var unitWork = _autofacServiceProvider.GetService<IUnitWork<OpenAuthDBContext>>();
var param = new SqlParameter("keyword", SqlDbType.NVarChar);
param.Value = "test%";
var users = unitWork.ExecProcedure<User>("sp_alluser", new []{param});
Console.WriteLine(JsonHelper.Instance.Serialize(users));
```
存储过程`sp_alluser`定义如下:
```sql
create procedure sp_alluser @keyword nvarchar(20) as
begin
select * from [user] where Account like @keyword;
end;
```
#### MySql
UnitWork提供执行存储过程接口`ExecProcedure`,使用如下:
``` csharp
var unitWork = _autofacServiceProvider.GetService<IUnitWork<OpenAuthDBContext>>();
var param = new MySqlParameter("keyword", SqlDbType.NVarChar);
param.Value = "test%";
var users = unitWork.ExecProcedure<User>("sp_alluser", new []{param});
Console.WriteLine(JsonHelper.Instance.Serialize(users));
```
::: warning 特别注意
这里的MySqlParameter命名空间使用的是
``` csharp
using MySqlConnector;
```
:::
存储过程`sp_alluser`定义如下:
```sql
create procedure sp_alluser(in keyword nvarchar(20))
begin
select * from user where Account like keyword;
end;
```

124
docs/core/wwwarchitect.md Normal file
View File

@@ -0,0 +1,124 @@
# 前端结构
OpenAuth.Mvc前端采用典型的mvc结构部署其中
* Views: 为静态资源页面最终会渲染成html实在不懂百度Asp.Net Mvc中的View
* wwwroot/js: 通用的js组件
* wwwroot/userJs: 业务相关的js代码。通常一个csthml页面对应一个userJs中的js文件。如`Categories\Index.cshtml`对应`userJs\categories.js`
```shell
|-- OpenAuth.Mvc
|-- Views
| |-- _ViewStart.cshtml
| |-- Categories
| | |-- Index.cshtml
| |-- DataPrivilegeRules
| | |-- index.cshtml
| |-- Error
| | |-- Auth.cshtml
| |-- FlowInstances
| | |-- Detail.cshtml
| | |-- Disposed.cshtml
| | |-- Edit.cshtml
| | |-- Index.cshtml
| | |-- Verification.cshtml
| | |-- Wait.cshtml
| |-- FlowSchemes
| | |-- Design.cshtml
| | |-- Index.cshtml
| | |-- NodeInfo.cshtml
| | |-- Preview.cshtml
| |-- Forms
| | |-- Edit.cshtml
| | |-- index.cshtml
| | |-- Preview.cshtml
| |-- Home
| | |-- git.cshtml
| | |-- Index.cshtml
| | |-- Main.cshtml
| |-- Login
| | |-- Index.cshtml
| |-- ModuleManager
| | |-- Assign.cshtml
| | |-- Index.cshtml
| |-- OpenJobs
| | |-- index.cshtml
| |-- OrgManager
| | |-- Index.cshtml
| |-- Redirects
| | |-- IdentityAuth.cshtml
| |-- Resources
| | |-- Assign.cshtml
| | |-- Index.cshtml
| |-- RoleManager
| | |-- Assign.cshtml
| | |-- Index.cshtml
| |-- Shared
| | |-- _Layout.cshtml
| |-- SysLogs
| | |-- index.cshtml
| |-- SysMessages
| | |-- index.cshtml
| |-- UserManager
| | |-- ChangePassword.cshtml
| | |-- Index.cshtml
| | |-- Profile.cshtml
| |-- WmsInboundOrderTbls
| |-- index.cshtml
|-- wwwroot
|-- css
| |-- formpreview.css
| |-- images.css
| |-- login.css
| |-- main.css
| |-- treetable.css
|-- js
|-- bodyTab.js
|-- bootstrap.js
|-- cookie.js
|-- droptree.js
|-- dtree.js
|-- flowlayout.js
|-- iconPicker.js
|-- index.js
|-- leftNav.js
|-- openauth.js
|-- slimscroll.js
|-- utils.js
|-- vue.js
|-- ztree.js
|-- userJs
|-- assignModule.js
|-- assignResource.js
|-- assignRole.js
|-- categories.js
|-- changePwd.js
|-- dataprivilegerules.js
|-- flowinstanceDetail.js
|-- flowInstanceDisposed.js
|-- flowInstanceEdit.js
|-- flowInstances.js
|-- flowInstanceWait.js
|-- flowSchemeDesign.js
|-- flowSchemePreview.js
|-- flowSchemes.js
|-- formEdit.js
|-- forms.js
|-- login.js
|-- main.js
|-- modules.js
|-- nodeInfo.js
|-- openjobs.js
|-- orgs.js
|-- preview.js
|-- profile.js
|-- resources.js
|-- roles.js
|-- syslogs.js
|-- sysmessages.js
|-- users.js
|-- verification.js
|-- wmsinboundordertbls.js
```