doc:添加cicd文档模块
This commit is contained in:
64
Yi.Doc.Md/02.框架功能模块教程/01.模块化.md
Normal file
64
Yi.Doc.Md/02.框架功能模块教程/01.模块化.md
Normal file
@@ -0,0 +1,64 @@
|
||||
## 简介
|
||||
通常,在Asp.NetCore中,**容器组装**过程 与 **管道模型组装** 过程 会将启动类文件变的非常长,同时也需要明确各个模块的依赖关系
|
||||
例如:
|
||||
我们需要仓储的功能,但是仓储的实现需要依赖Sqlsugar
|
||||
老的引入写法:
|
||||
``` cs
|
||||
service.AddUow();
|
||||
service.AddSqlsugar();
|
||||
......
|
||||
var app=service.Build();
|
||||
app.UseSqlsugar();
|
||||
......
|
||||
```
|
||||
这个文件会变得非常长,同时如果有顺序依赖关系的模块,还需按顺序组装
|
||||
例如:
|
||||
在Asp.NetCore,我们只有先鉴权才能进行授权操作
|
||||
当模块越来越多,我们维护起来将越来越困难,所以引入了模块化功能
|
||||
|
||||
## 使用
|
||||
每一个类库都可以有自己的模块化文件,我们通常命名为类库全名+Module
|
||||
例如:`Yi.Template.Application`的模块类叫做`YiTemplateApplicationModule`
|
||||
|
||||
另外,该模块类实现`AbpModule`基类
|
||||
ConfigureServices:用来配置容器服务
|
||||
OnApplicationInitialization:管道模型组装后执行
|
||||
|
||||
Abp内置`DependsOn`特性标签,可进行维护各个模块之间的依赖关系
|
||||
|
||||
## 完整例子
|
||||
创建模块化文件:
|
||||
``` cs
|
||||
using Volo.Abp.Caching;
|
||||
using Volo.Abp.Domain;
|
||||
using Volo.Abp.Modularity;
|
||||
using Yi.Abp.Domain.Shared;
|
||||
using Yi.Framework.Bbs.Domain;
|
||||
using Yi.Framework.Mapster;
|
||||
using Yi.Framework.Rbac.Domain;
|
||||
|
||||
namespace Yi.Abp.Domain
|
||||
{
|
||||
[DependsOn(
|
||||
typeof(YiAbpDomainSharedModule),
|
||||
|
||||
|
||||
typeof(YiFrameworkRbacDomainModule),
|
||||
typeof(YiFrameworkBbsDomainModule),
|
||||
|
||||
typeof(YiFrameworkMapsterModule),
|
||||
typeof(AbpDddDomainModule),
|
||||
typeof(AbpCachingModule)
|
||||
)]
|
||||
public class YiAbpDomainModule : AbpModule
|
||||
{
|
||||
public virtual void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnPreApplicationInitialization(ApplicationInitializationContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
60
Yi.Doc.Md/02.框架功能模块教程/02.动态Api.md
Normal file
60
Yi.Doc.Md/02.框架功能模块教程/02.动态Api.md
Normal file
@@ -0,0 +1,60 @@
|
||||
## 简介
|
||||
控制器层通常不包含业务的,我们控制器的代码经常是如下:
|
||||
``` cs
|
||||
[HttpGet]
|
||||
[route("Info")]
|
||||
pulic IActionResult GetInfo()
|
||||
{
|
||||
retrun Ok(_service.GetInfo());
|
||||
}
|
||||
```
|
||||
我们不仅要创建控制器文件,还要写出应用层到控制器的方法,将业务的数据通过控制器暴露出去
|
||||
> 控制器只做转发,没有做任何事情,形成了大量的冗余代码
|
||||
|
||||
## 如何使用
|
||||
> 推荐直接在应用层中直接使用
|
||||
|
||||
使用动态Api,需要3个条件
|
||||
1. 任何一个类,实现`IRemoteService`接口
|
||||
2. 该类需要加入DI容器
|
||||
3. 在管道模型中,配置动态Api服务:
|
||||
|
||||
> 通常我们直接继承`ApplicationService`即可,因为该类实现了`IRemoteService`
|
||||
``` cs
|
||||
//动态Api
|
||||
Configure<AbpAspNetCoreMvcOptions>(options =>
|
||||
{
|
||||
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly, options => options.RemoteServiceName = "default");
|
||||
});
|
||||
```
|
||||
|
||||
根据方法名自动映射Http方法及路由
|
||||
例如:
|
||||
- GetInfo:Get请求
|
||||
- UpdateInfo:Put请求
|
||||
- RemoveInfo: Del请求
|
||||
- CreateInfo: Post请求
|
||||
|
||||
|
||||
## 完整例子
|
||||
``` cs
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
namespace Yi.Abp.Application.Services
|
||||
{
|
||||
public class TestService : ApplicationService
|
||||
{
|
||||
/// <summary>
|
||||
/// 你好世界
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public string GetHelloWorld(string? name)
|
||||
{
|
||||
return name ?? "HelloWord";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
35
Yi.Doc.Md/02.框架功能模块教程/03.依赖注入.md
Normal file
35
Yi.Doc.Md/02.框架功能模块教程/03.依赖注入.md
Normal file
@@ -0,0 +1,35 @@
|
||||
## 简介
|
||||
熟悉Asp.NetCore的小伙伴们,对依赖注入可太熟悉,这里也不在过多的讲述依赖注入知识
|
||||
默认内置的注入方式,通常是在启动类文件,一个一个手动注入,例如:
|
||||
``` cs
|
||||
service.Addsingle<接口,类>()
|
||||
```
|
||||
同样,当服务过多,添加服务的代码会显的非常长,不够优雅
|
||||
可以使用框架内置的接口
|
||||
- IScopedDependency
|
||||
- ISingletonDependency
|
||||
- ITransientDependency
|
||||
|
||||
也可以使用框架内置的特性
|
||||
- DependencyAttribute
|
||||
- ExposeServicesAttribute
|
||||
|
||||
> 使用特性,可以指定特定类、接口作为抽象
|
||||
## 如何使用
|
||||
#### 特性方式:
|
||||
在实现类上标注特性即可
|
||||
``` cs
|
||||
[ExposeServices(typeof(ITestService))]
|
||||
[Dependency(ServiceLifetime.Transient)]
|
||||
public class Test
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
#### 接口方式:
|
||||
同理,根据不同的接口,选择不同的生命周期,自动会优先找自动以`I+类名`的接口作为抽象
|
||||
``` cs
|
||||
public class Test:ITest,ISingletonDependency
|
||||
{
|
||||
}
|
||||
```
|
||||
14
Yi.Doc.Md/02.框架功能模块教程/04.属性注入.md
Normal file
14
Yi.Doc.Md/02.框架功能模块教程/04.属性注入.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## 简介
|
||||
默认推荐的构造函数注入,依赖关系会非常明确
|
||||
但是,会给程序带来大量的重复依赖注入代码,构造函数会非常的冗余
|
||||
所以,在Abp的中,内置了属性注入方式
|
||||
> 不是开玩笑,万不得已,最好别用。我也被坑过很多次,带来的弊端也非常明显,难以调试,且依赖关系不清晰,生命周期也是在构造函数之后
|
||||
|
||||
## 使用方式
|
||||
使用极为简单:
|
||||
``` cs
|
||||
public IArticleRepository ArticleRepository { get; set; }
|
||||
```
|
||||
在具备get与set方法的属性上,打上Autowired特性即可,在该类被注入时候,该属性会在容器中寻找并且赋值
|
||||
|
||||
我们的实现方式,是通过AutoFac的模块,你需要在启动的Host中添加autofac的属性注入模块:
|
||||
41
Yi.Doc.Md/02.框架功能模块教程/05.当前用户.md
Normal file
41
Yi.Doc.Md/02.框架功能模块教程/05.当前用户.md
Normal file
@@ -0,0 +1,41 @@
|
||||
## 简介
|
||||
如何获取当前请求用户信息?这个问题有很多个答案
|
||||
|
||||
常规是通过HttpContext对象进行获取,它通常是在ControllerBase中,控制器中内置了HttpContext对象
|
||||
也可以通过依赖注入HttpContext访问器中获取
|
||||
|
||||
> 但是,他们都不够优雅,原因:与HttpContext具备了强耦合,如果对于没有HttpContext,将会非常的难维护,例如:单元测速
|
||||
|
||||
你可以依赖注入使用:`ICurrentUser`
|
||||
它是瞬态注入,但是它能够获取当前作用域的用户信息
|
||||
## 如何使用
|
||||
任何地方,依赖注入:`ICurrentUser`
|
||||
它包含属性:
|
||||
``` cs
|
||||
public interface ICurrentUser
|
||||
{
|
||||
//是否授权
|
||||
public bool IsAuthenticated { get; }
|
||||
//id
|
||||
public Guid Id { get; }
|
||||
//用户名
|
||||
public string UserName { get; }
|
||||
//租户id
|
||||
public Guid TenantId { get; }
|
||||
//邮件
|
||||
public string Email { get; }
|
||||
|
||||
public bool EmailVerified { get; }
|
||||
//电话
|
||||
public string PhoneNumber { get; }
|
||||
|
||||
public bool PhoneNumberVerified { get; }
|
||||
//角色codes
|
||||
public string[]? Roles { get; }
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
直接使用即可
|
||||
|
||||
> 注意,当前用户功能默认是继承到Core模块,所以你无需进行任何引用,直接使用即可
|
||||
26
Yi.Doc.Md/02.框架功能模块教程/06.SqlSugarORM.md
Normal file
26
Yi.Doc.Md/02.框架功能模块教程/06.SqlSugarORM.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## 简介
|
||||
在C#强大的语法下,Orm也是极度的优雅
|
||||
本框架默认集成Sqlsugar Orm,与YiFramework拥有相同理念
|
||||
> 从用户体验出发,用起来爽,使用体验极佳
|
||||
|
||||
你可以查略 [Sqlsguar官网](https://www.donet5.com/Home/Doc)学习
|
||||
## 如何使用
|
||||
默认已经集成SqlSugar模块,可依赖注入`ISqlSugarDbContext`即可,我们称做它为Db,用于操作数据库
|
||||
|
||||
> 不推荐直接使用db,大部分的操作数据方式使用仓储完全够用`ISqlSugarRepository<Entity, Guid> repository`或`IRepository<Entity, Guid> repository`
|
||||
|
||||
由于Querable对象用起来并没有到达SugarQuerable的爽感,且也不想让每个复杂查询都通过仓储进行扩展,这会导致用户使用感较差
|
||||
|
||||
所以经过各类平衡考虑,YiFramework框架与Sqlsugar是有轻量的`耦合性`的,框架提供Sqlsugar抽象层,避免过重的耦合,意味着,你可以在`大部分`地方使用Sqlsugar的操作,这在真正的业务项目来说,使用非常的方便,与Sqlsugar保持有一致的观念
|
||||
|
||||
我们已经集成SqlSugarCore模块在Abp.vNext中的
|
||||
- Crud
|
||||
- 仓储
|
||||
- 工作单元
|
||||
- 审计日志
|
||||
- 逻辑删除
|
||||
- 数据过滤
|
||||
- 领域事件
|
||||
- 逻辑删除
|
||||
|
||||
意味着,可以平滑的直接使用Abp.vNext的这些功能
|
||||
28
Yi.Doc.Md/02.框架功能模块教程/07.仓储.md
Normal file
28
Yi.Doc.Md/02.框架功能模块教程/07.仓储.md
Normal file
@@ -0,0 +1,28 @@
|
||||
## 简介
|
||||
使用仓储用于操作数据库数据,封装通用增删改查等方式
|
||||
> `ISqlsugarRepository<TEntity>`仓储内置了Sqlsugar Db,具有一定的强耦合,但是使用起来会非常的舒服方便
|
||||
|
||||
** 原因:**Queryable对象是微软内置的查询对象,可以使用linq语法,同时也是为了Efcore的查询对象,Sqlsugar 的查询对象为SugarQueryable对象,两者并不兼容,SugarQueryable的功能远远大与Queryable,为此Sqlsugar不会限制自己而兼容Queryable对象
|
||||
|
||||
## 使用方式
|
||||
方式1:依赖注入`IRepository<TEntity>`接口即可
|
||||
|
||||
方式2:依赖注入`IRepository<TEntity,Guid>`接口即可
|
||||
|
||||
方式3:依赖注入`ISqlSugarRepository<TEntity>`接口即可
|
||||
|
||||
方式4:依赖注入`ISqlSugarRepository<TEntity,Guid>`接口即可
|
||||
|
||||
方式5:继承`SqlSugarRepository<TEntity,Guid>`基类,自定义仓储,注入自己的仓储接口,例如写一个`StudentRepository`继承`SqlSugarRepository<TEntity,Guid>`,再实现自己的`IStudentRepository`,后续使用`IStudentRepository`依赖注册进行使用即可
|
||||
|
||||
> 推荐简单常用`ISqlSugarRepository<TEntity,Guid>`的注入
|
||||
|
||||
`ISqlSugarRepository`内置了非常多的通用数据库操作方法,同时也内置了`ISqlsugarClient`Db对象在其中
|
||||
|
||||
内置方法非常多
|
||||
- 查询
|
||||
- 删除
|
||||
- 修改
|
||||
- 添加
|
||||
- 分页查询
|
||||
- Db对象
|
||||
56
Yi.Doc.Md/02.框架功能模块教程/08.Crud增删改查.md
Normal file
56
Yi.Doc.Md/02.框架功能模块教程/08.Crud增删改查.md
Normal file
@@ -0,0 +1,56 @@
|
||||
## 简介
|
||||
> 想做一个快乐的Crud boy??好,满足你
|
||||
|
||||
可能绝大部分简单的业务,真的只是不用类型的Crud,大量的重复代码,使用cv方式,不够优雅
|
||||
|
||||
框架内部内部封装各种场景下的crud
|
||||
|
||||
## 使用
|
||||
在应用层继承`YiCrudAppService`crud服务即可
|
||||
在这之前,你应该先了解各个dto的作用:
|
||||
|
||||
> 注意,我们当然可以直接使用Abp中的`CrudAppService`,但由于Abp内置的Crud还缺少一些常用的接口,比如批量删除等方式,所以推荐使用`YiCrudAppService`,使用上完全没有区别
|
||||
|
||||
``` cs
|
||||
- TGetOutputDto (单查返回的dto)
|
||||
- TGetListOutputDto (多查返回的dto)
|
||||
- TGetListInput (多查的条件)
|
||||
- TCreateInput (创建的dto)
|
||||
- TUpdateInput (更新的dto)
|
||||
```
|
||||
根据Dto业务场景,它有很多种选项,依次为:
|
||||
``` cs
|
||||
- YiCrudAppService<TEntity, TEntityDto, TKey>
|
||||
- YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput>
|
||||
- YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>
|
||||
- YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
|
||||
- YiCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
|
||||
```
|
||||
dto可以放到`Application.Contracts`层,同理接口继承`IYiCrudAppService`即可
|
||||
```cs
|
||||
- YiCrudAppService<TEntityDto, TKey>
|
||||
- YiCrudAppService<TEntityDto, TKey, TGetListInput>
|
||||
- YiCrudAppService<TEntityDto, TKey, TGetListInput, TCreateInput>
|
||||
- YiCrudAppService<TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
|
||||
- YiCrudAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
|
||||
```
|
||||
> 可以发现,接口,不应该与实体有直接关系
|
||||
|
||||
其中,在YiCrudAppService中,我们提供了一些内置的方法:
|
||||
```cs
|
||||
public virtual async Task<TGetOutputDto> CreateAsync(TCreateInput input)
|
||||
public virtual async Task<bool> DeleteAsync(string id)
|
||||
public virtual async Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input)
|
||||
public virtual async Task<TGetOutputDto> GetAsync(TKey id)
|
||||
public virtual async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
|
||||
```
|
||||
同时还有映射关系:
|
||||
``` cs
|
||||
protected virtual Task<TGetOutputDto> MapToGetOutputDtoAsync(TEntity entity)
|
||||
protected virtual Task<List<TGetListOutputDto>> MapToGetListOutputDtosAsync(List<TEntity> entities)
|
||||
protected virtual Task<TGetListOutputDto> MapToGetListOutputDtoAsync(TEntity entity)
|
||||
protected virtual Task<TGetOutputDto> MapToGetOutputDtoAsync(TEntity entity)
|
||||
protected virtual Task<List<TGetListOutputDto>> MapToGetListOutputDtosAsync(List<TEntity> entities)
|
||||
protected virtual Task<TGetListOutputDto> MapToGetListOutputDtoAsync(TEntity entity)
|
||||
```
|
||||
另外,它也提供了对应的`仓储`及`当前用户`等常用属性
|
||||
42
Yi.Doc.Md/02.框架功能模块教程/09.审计日志.md
Normal file
42
Yi.Doc.Md/02.框架功能模块教程/09.审计日志.md
Normal file
@@ -0,0 +1,42 @@
|
||||
## 简介
|
||||
审计日志是对数据的操作记录
|
||||
例如:
|
||||
1. 数据的创建者
|
||||
2. 数据的创建时间
|
||||
3. 数据的更新者
|
||||
4. 数据的更新时间
|
||||
|
||||
对于重要的数据,我们应该提供审计日志功能,方便进行数据追溯
|
||||
框架内部已`自动集成`,使用起来非常简单
|
||||
## 如何使用
|
||||
我们把全部的审计日志封装一个对象
|
||||
你的**实体**可直接继继承或者实现接口
|
||||
AuditedObject与IAuditedObject
|
||||
|
||||
它包含4个属性字段,
|
||||
``` cs
|
||||
public DateTime CreationTime { get; set; }= DateTime.Now;
|
||||
|
||||
public Guid? CreatorId { get; set; }
|
||||
|
||||
public Guid? LastModifierId { get; set; }
|
||||
|
||||
public DateTime? LastModificationTime { get; set; }
|
||||
|
||||
```
|
||||
|
||||
**在执行插入的时候:**
|
||||
会自动为`CreationTime` 与 `CreatorId` 赋值
|
||||
|
||||
|
||||
**在执行更新的时候:**
|
||||
会自动为`LastModificationTime` 与 `LastModifierId` 赋值
|
||||
|
||||
当然,如果只需要部分的审计日志,你完全可以实现单独的接口
|
||||
分别为:
|
||||
``` cs
|
||||
IHasCreationTime
|
||||
IMayHaveCreator
|
||||
IModificationAuditedObject
|
||||
IHasModificationTime
|
||||
```
|
||||
47
Yi.Doc.Md/02.框架功能模块教程/10.工作单元.md
Normal file
47
Yi.Doc.Md/02.框架功能模块教程/10.工作单元.md
Normal file
@@ -0,0 +1,47 @@
|
||||
## 简介
|
||||
> 工作单元模式是“维护一个被业务事务影响的对象列表,协调变化的写入和并发问题的解决”
|
||||
|
||||
它的作用
|
||||
1. 事务相关
|
||||
2. 共用连接
|
||||
...
|
||||
|
||||
## 如何使用
|
||||
依赖注入`IUnitOfWorkManager`,使用`CreateContext`创建一个`IUnitOfWork`工作单元
|
||||
在工作单元内部,可提交,回滚,获取仓储
|
||||
``` cs
|
||||
bool IsTran { get; set; }
|
||||
bool IsCommit { get; set; }
|
||||
bool IsClose { get; set; }
|
||||
|
||||
IRepository<T> GetRepository<T>();
|
||||
bool Commit();
|
||||
```
|
||||
|
||||
> 注意,在除Get请求上,其他请求默认都开启了工作单元(post、put、delelte)
|
||||
|
||||
## 完整例子
|
||||
``` cs
|
||||
private IUnitOfWorkManager _unitOfWorkManager { get; set; }
|
||||
public void Test()
|
||||
{
|
||||
using (var uow = _unitOfWorkManager.CreateContext())
|
||||
{
|
||||
//仓储执行各种操作
|
||||
|
||||
//统一提交
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
## 特性方式
|
||||
还可以通过`[UnitOfWork]`特性,打在方法上,该方法便会当作一个事务进行提交
|
||||
``` cs
|
||||
[UnitOfWork]
|
||||
public void Test()
|
||||
{
|
||||
//仓储执行各种操作
|
||||
}
|
||||
```
|
||||
|
||||
92
Yi.Doc.Md/02.框架功能模块教程/11.种子数据.md
Normal file
92
Yi.Doc.Md/02.框架功能模块教程/11.种子数据.md
Normal file
@@ -0,0 +1,92 @@
|
||||
## 简介
|
||||
种子数据一直都是一个很繁琐的东西,例如在初始化数据的时候,添加默认用户
|
||||
可以通过导入sql的方式进行添加种子数据,也可以通过程序代码中自动初始化数据
|
||||
我们目前提供后者
|
||||
|
||||
## 如何使用
|
||||
一切的根源,来源自:`IDataSeedContributor`
|
||||
直接使用实现`IDataSeedContributor`接口,我们只需要实现 `SeedAsync(DataSeedContext context)`即可
|
||||
|
||||
在实现类上,要将该类加入容器中,推荐通过内置的依赖注入模块
|
||||
|
||||
当然,对于扩展,你可以重写其他的方法
|
||||
|
||||
#### 其他方式使用
|
||||
另外,你可以直接依赖注入,直接使用IDataSeeder SeedAsync方法,重新手动执行种子数据
|
||||
> 默认在程序启动的时候,会根据配置文件选择,是否执行种子数据
|
||||
|
||||
## 完整例子
|
||||
``` cs
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Data;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using Volo.Abp.Guids;
|
||||
using Yi.Framework.Rbac.Domain.Entities;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.Bbs.SqlSugarCore.DataSeeds
|
||||
{
|
||||
public class ConfigDataSeed : IDataSeedContributor, ITransientDependency
|
||||
{
|
||||
private ISqlSugarRepository<ConfigEntity> _repository;
|
||||
public ConfigDataSeed(ISqlSugarRepository<ConfigEntity> repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
public async Task SeedAsync(DataSeedContext context)
|
||||
{
|
||||
if (!await _repository.IsAnyAsync(x => true))
|
||||
{
|
||||
await _repository.InsertManyAsync(GetSeedData());
|
||||
}
|
||||
}
|
||||
public List<ConfigEntity> GetSeedData()
|
||||
{
|
||||
List<ConfigEntity> entities = new List<ConfigEntity>();
|
||||
ConfigEntity config1 = new ConfigEntity()
|
||||
{
|
||||
ConfigKey = "bbs.site.name",
|
||||
ConfigName = "站点名称",
|
||||
ConfigValue = "意社区"
|
||||
};
|
||||
entities.Add(config1);
|
||||
|
||||
ConfigEntity config2 = new ConfigEntity()
|
||||
{
|
||||
ConfigKey = "bbs.site.author",
|
||||
ConfigName = "站点作者",
|
||||
ConfigValue = "橙子"
|
||||
};
|
||||
entities.Add(config2);
|
||||
|
||||
ConfigEntity config3 = new ConfigEntity()
|
||||
{
|
||||
ConfigKey = "bbs.site.icp",
|
||||
ConfigName = "站点Icp备案",
|
||||
ConfigValue = "赣ICP备20008025号"
|
||||
};
|
||||
entities.Add(config3);
|
||||
|
||||
|
||||
ConfigEntity config4 = new ConfigEntity()
|
||||
{
|
||||
ConfigKey = "bbs.site.bottom",
|
||||
ConfigName = "站点底部信息",
|
||||
ConfigValue = "你好世界"
|
||||
};
|
||||
entities.Add(config4);
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
80
Yi.Doc.Md/02.框架功能模块教程/12.Jwt鉴权.md
Normal file
80
Yi.Doc.Md/02.框架功能模块教程/12.Jwt鉴权.md
Normal file
@@ -0,0 +1,80 @@
|
||||
## 简介
|
||||
> 鉴权是用于解析用户的令牌,知道用户是否携带令牌,并且知道用户信息是谁
|
||||
|
||||
改鉴权使用的是微软Asp.NetCore扩鉴权扩展方式
|
||||
程序模块已内置
|
||||
``` cs
|
||||
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ClockSkew = TimeSpan.Zero,
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = jwtOptions.Issuer,
|
||||
ValidAudience = jwtOptions.Audience,
|
||||
RequireExpirationTime = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
|
||||
};
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var accessToken = context.Request.Query["access_token"];
|
||||
if (!string.IsNullOrEmpty(accessToken))
|
||||
{
|
||||
context.Token = accessToken;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
## 如何使用
|
||||
默认已经集成,所以在使用方面,可要求客户端添加标准的jwtbear头即可
|
||||
|
||||
swagger 接口文档中,已集成,直接输入jwttoken即可
|
||||

|
||||
|
||||
我们采用的是HSA对称加密方式,只需要具备密钥
|
||||
对应的配置文件
|
||||
``` json
|
||||
//鉴权
|
||||
"JwtOptions": {
|
||||
"Issuer": "https://ccnetcore.com",
|
||||
"Audience": "https://ccnetcore.com",
|
||||
"SecurityKey": "zqxwcevrbtnymu312412ihe9rfwhe78rh23djoi32hrui3ryf9e8wfh34iuj54y0934uti4h97fgw7hf97wyh8yy69520",
|
||||
"ExpiresMinuteTime": 86400
|
||||
}
|
||||
```
|
||||
## Token如何来
|
||||
那肯定是登录啊,登录接口会返回Token
|
||||
|
||||
那如何制作Token?直接上代码,下面这个也是登录的创建token的方式
|
||||
|
||||
``` cs
|
||||
/// <summary>
|
||||
/// 创建令牌
|
||||
/// </summary>
|
||||
/// <param name="dic"></param>
|
||||
/// <returns></returns>
|
||||
private string CreateToken(Dictionary<string, object> dic)
|
||||
{
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecurityKey));
|
||||
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
var claims = dic.Select(x => new Claim(x.Key, x.Value.ToString())).ToList();
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: _jwtOptions.Issuer,
|
||||
audience: _jwtOptions.Audience,
|
||||
claims: claims,
|
||||
expires: DateTime.Now.AddSeconds(_jwtOptions.ExpiresMinuteTime),
|
||||
notBefore: DateTime.Now,
|
||||
signingCredentials: creds);
|
||||
string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||
|
||||
return returnToken;
|
||||
}
|
||||
```
|
||||
18
Yi.Doc.Md/02.框架功能模块教程/13.接口授权.md
Normal file
18
Yi.Doc.Md/02.框架功能模块教程/13.接口授权.md
Normal file
@@ -0,0 +1,18 @@
|
||||
## 简介
|
||||
> 授权必须基于鉴权之后,知道了用户的信息,根据用户权限列表进行判断是否有权限进入
|
||||
|
||||
框架内部集成授权方式,并非为Asp.netcore授权方式,而是提供一种更简单的方式
|
||||
使用起来非常简单
|
||||
|
||||
## 使用
|
||||
只需要在需要授权的接口上打上特性 `[Permission("code")]`接口
|
||||
|
||||
code为登录时候颁发的token中的权限,如果该用户的token 权限列表中不包含code,将被会拦截,并提示未授权,被拒绝
|
||||
|
||||
``` cs
|
||||
[Permission("system:user:delete")]
|
||||
public override async Task DeleteAsync(Guid id)
|
||||
{
|
||||
await base.DeleteAsync(id);
|
||||
}
|
||||
```
|
||||
48
Yi.Doc.Md/02.框架功能模块教程/14.异常处理.md
Normal file
48
Yi.Doc.Md/02.框架功能模块教程/14.异常处理.md
Normal file
@@ -0,0 +1,48 @@
|
||||
## 简介
|
||||
当程序出现异常之后,框架需要记录,同时反馈前端对应的信息
|
||||
它通过`全局错误中间件`实现
|
||||
|
||||
错误后,将统一返回以下模型格式:
|
||||
``` cs
|
||||
public class RemoteServiceErrorInfo
|
||||
{
|
||||
|
||||
public string? Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// message.
|
||||
/// </summary>
|
||||
public string? Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// details.
|
||||
/// </summary>
|
||||
public string? Details { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// data.
|
||||
/// </summary>
|
||||
public object? Data { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
框架内部错误分为三大类:
|
||||
#### 系统内部错误
|
||||
> httpCode:500
|
||||
系统不能处理、或未发现的错误,需要即使进行修复
|
||||
#### 业务友好错误
|
||||
> httpCode:403
|
||||
跟业务相关,业务请求不合理,例如:登录失败、数据重复
|
||||
#### 授权错误
|
||||
> httpCode:401
|
||||
跟权限相关,代表当前用户权限不足
|
||||
|
||||
## 使用
|
||||
你可以在程序任何地方进行抛出错误
|
||||
``` cs
|
||||
throw new Exception("系统错误");//状态码500
|
||||
throw new UserFriendlyException("业务错误");//状态码403
|
||||
throw new NotImplementedException("未实现");//状态码501
|
||||
throw new UserFriendlyException("花里胡哨错误","401");//状态码401
|
||||
```
|
||||
Abp内部将自动抓取,并返回给前端
|
||||
Reference in New Issue
Block a user