甚么是OSharp
OSharpNS全称OSharp Framework with .NetStandard2.0,是一个基于.NetStandard2.0
开辟的一个.NetCore
疾速开辟框架。这个框架应用最新稳定版的.NetCore SDK
(以后是.NET Core 2.2),对 AspNetCore 的设置装备摆设、依靠注入、日记、缓存、实体框架、Mvc(WebApi)、身份认证、权限受权等模块举行更高一级的自动化封装,并范例了一套营业完成的代码构造与操纵流程,使 .Net Core 框架更易于应用到现实项目开辟中。
- 开源地点:https://github.com/i66soft/osharp
- 官方示例:https://www.osharp.org
- 文档中间:https://docs.osharp.org
- VS 插件:https://marketplace.visualstudio.com/items?itemName=LiuliuSoft.osharp
- 系列示例:https://github.com/i66soft/osharp-docs-samples
概述
一个模块的 API层(Web层),重要卖力以下几个方面的事情:
- 吸收
前端层
提交的数据查询请求,应用效劳层
供应的IQueryable<T>
查询数据源,查询出须要的数据返回前端 - 吸收
前端层
提交的营业处置惩罚请求,挪用效劳层
的效劳,处置惩罚营业需求,并将操纵效果返回前端 - 应用MVC的
Area-Controller-Action
的条理干系,团结[ModuleInfo]
特征, 界说 Api模块Module
的 树形构造构造,API模块 的 依靠干系,构建出Module
的树形数据 - 界说 API 的
可接见体式格局
,API的接见体式格局可分为匿名接见
,登录接见
和脚色接见
- 界说自动事件提交,触及数据库调换的营业,可在API界说自动事件提交,在营业层完成营业时便可不消斟酌事件的题目
全部历程以下图所示
API层 代码结构
API层 代码结构剖析
API层 等于Web网站效劳端的MVC掌握器,掌握器可按粒度须要分歧,分为模块掌握器和单实体掌握器,这个由营业需求决议。
一般,背景治理的掌握器,是实体粒度的,即每一个实体都有一个掌握器,而且存在于 /Areas/Admin/Controlers
文件夹内。
博客模块的 API 层掌握器,以下图所示:
src 源代码文件夹
└─Liuliu.Blogs.Web 项目Web工程
└─Areas 地区文件夹
└─Admin 治理地区文件夹
└─Controllers 治理掌握器文件夹
└─Blogs 博客模块文件夹
├─BlogController.cs 博客治理掌握器
└─PostController.cs 文章治理掌握器
API界说及接见掌握的基本建设
API界说
API界说即MVC或WebApi的 Area-Controller-Action
界说,为轻易及范例此步调的事情,OSharp界说了一些 API基本掌握器基类
,继续这些基类,很轻易完成API界说。
ApiController
ApiController
用于非Area的Api掌握器,基类增添了 操纵审计[AuditOperation]
,[ApiController]
特征,并界说了一个 [Route("api/[controller]/[action]")]
的路由特征
/// <summary>
/// WebApi掌握器基类
/// </summary>
[AuditOperation]
[ApiController]
[Route("api/[controller]/[action]")]
public abstract class ApiController : Controller
{
/// <summary>
/// 猎取或设置 日记对象
/// </summary>
protected ILogger Logger => HttpContext.RequestServices.GetLogger(GetType());
}
AreaApiController
与 无地区掌握器基类ApiController
相对应,关于地区掌握器,也界说了一个基类 AreaApiController
/// <summary>
/// WebApi的地区掌握器基类
/// </summary>
[AuditOperation]
[ApiController]
[Route("api/[area]/[controller]/[action]")]
public abstract class AreaApiController : Controller
{ }
AdminApiController
关于相称经常使用的 治理Admin
地区,也一样界说了一个掌握器基类AdminApiController
,此基类继续于AreaApiController
,并增添了地区特征[Area("Admin")]
和脚色接见限定特征[RoleLimit]
[Area("Admin")]
[RoleLimit]
public abstract class AdminApiController : AreaApiController
{ }
博客模块API完成
[Description("治理-博客信息")]
public class BlogController : AdminApiController
{ }
[Description("治理-文章信息")]
public class PostController : AdminApiController
{ }
Module树形构造及依靠
ModuleInfoAttribute
为了形貌 API的层级干系,OSharp界说了一个ModuleInfoAttribute
特征,把以后功用(Controller或许Action)封装为一个模块(Module)节点,能够设置模块依靠的其他功用,模块的地位信息等。此特征用于体系初始化时自动提取模块树信息Module。
/// <summary>
/// 形貌把以后功用(Controller或许Action)封装为一个模块(Module)节点,能够设置模块依靠的其他功用,模块的地位信息等
/// 此特征用于体系初始化时自动提取模块树信息Module
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ModuleInfoAttribute : Attribute
{
/// <summary>
/// 猎取或设置 模块称号,为空则取功用称号
/// </summary>
public string Name { get; set; }
/// <summary>
/// 猎取或设置 模块代码,为空则取功用Action名
/// </summary>
public string Code { get; set; }
/// <summary>
/// 猎取或设置 条理序号
/// </summary>
public double Order { get; set; }
/// <summary>
/// 猎取或设置 模块地位,父级模块,模块在树节点的地位,默许取地点类的地位,须要在定名空间与以后类之间加模块,才设置此值
/// </summary>
public string Position { get; set; }
/// <summary>
/// 猎取或设置 父级地位模块称号,须要在定名空间与以后类之间加模块,才设置此值
/// </summary>
public string PositionName { get; set; }
}
[ModuleInfo]
特征重要有两种用法:
- 在
Controller
上,重要掌握模块的递次Order
,模块的地位Position
,模块称号PositionName
,比方:
[ModuleInfo(Position = "Blogs", PositionName = "博客模块")]
[Description("治理-博客信息")]
public class BlogController : AdminApiController
{ }
- 在
Action
上,重要用于标注哪些Action是作为可权限分派的API,一般无需应用属性,比方:
/// <summary>
/// 读取博客
/// </summary>
/// <returns>博客页列表</returns>
[HttpPost]
[ModuleInfo]
[Description("读取")]
public PageData<BlogOutputDto> Read(PageRequest request)
{ }
DependOnFunctionAttribute
因为营业的关联性和UI的合理结构,API功用点并 不是零丁存在 的,要完成一个完全的操纵,各个API功用点可能会 存在依靠性。比方:
- 在要举行治理列表中的
新增、更新、删除
等操纵,起首要能进入列表,即列表数据的读取
操纵,那末新增、更新、删除
等操纵就对读取
操纵存在依靠需求。 - 关于
新增、更新
操纵,一般须要对数据举行唯一性考证
,那末也会存在依靠干系
为了在代码中形貌这些依靠干系,OSharp中界说了DependOnFunctionAttribute
特征,在Action上标注以后API对其他API(可跨Controller,跨Area)的依靠干系。
/// <summary>
/// 模块依靠的功用信息,用于提取模块信息Module时肯定模块依靠的功用(模块依靠以后功用和此特征设置的其他功用)
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public class DependOnFunctionAttribute : Attribute
{
/// <summary>
/// 初始化一个<see cref="DependOnFunctionAttribute"/>范例的新实例
/// </summary>
public DependOnFunctionAttribute(string action)
{
Action = action;
}
/// <summary>
/// 猎取或设置 地区称号,为null(不设置)则应用以后功用地点地区,如要透露表现无地区的功用,需设置为空字符串""
/// </summary>
public string Area { get; set; }
/// <summary>
/// 猎取或设置 掌握器称号,为null(不设置)则应用以后功用地点掌握器
/// </summary>
public string Controller { get; set; }
/// <summary>
/// 猎取 功用称号Action,不克不及为空
/// </summary>
public string Action { get; }
}
以下示例,注解治理列表中的新增文章
营业对文章读取
有依靠干系
/// <summary>
/// 新增文章
/// </summary>
/// <param name="dtos">新增文章信息</param>
/// <returns>JSON操纵效果</returns>
[HttpPost]
[ModuleInfo]
[DependOnFunction("Read")]
[ServiceFilter(typeof(UnitOfWorkAttribute))]
[Description("新增")]
public async Task<AjaxResult> Create(PostInputDto[] dtos)
{ }
API接见掌握
API的接见掌握,分为三种:
- 匿名接见
AllowAnonymousAttribute
:透露表现以后功用不须要登录便可接见,疏忽登录状况和脚色请求 - 登录接见
LoginedAttribute
:透露表现以后功用须要登录能力接见,未登录谢绝接见 - 脚色接见
RoleLimitAttribute
:透露表现以后功用须要登录而且用户具有指定脚色,能力接见,未登录或许登录但未具有指定脚色,谢绝接见
API接见掌握的掌握递次依照 就近准绳,即离要实行的功用近来的谁人限定见效。以Controller上的标注与Action上的标注为例:
- Controller无,Action无,不限定
- Controller有,Action无,以Controller为准
- Controller无,Action有,以Action为准
- Controller有,Action有,以Action为准
在AdminApiController
基类中,已设置了[RoleLimit]
,透露表现Admin地区中的一切Controller和Action的默许接见掌握体式格局就是 脚色接见。
[Area("Admin")]
[RoleLimit]
public abstract class AdminApiController : AreaApiController
{ }
如想分外掌握,则须要在完成Action的时刻举行零丁设置装备摆设
[HttpPost]
[ModuleInfo]
[Logined]
[Description("读取")]
public PageData<BlogOutputDto> Read(PageRequest request)
{ }
自动事件提交
在传统框架中,事件的提交是在营业层完成完营业操纵以后即手动提交的,这类体式格局能更精准的掌握事件的终了地位,但也有不克不及实用的状况,比方当一个营业触及多个效劳的时刻,每一个效劳各自提交了事件,便没法包管一切操纵在一个完全的事件上举行了。
为此,OSharp框架提出了一种新的事件提交体式格局:在Action中经由过程Mvc的Filter来自动提交事件。
自动提交事件是经由过程以下的UnitOfWorkAttribute
完成的:
/// <summary>
/// 自动事件提交过滤器,在<see cref="OnResultExecuted"/>要领中实行<see cref="IUnitOfWork.Commit()"/>举行事件提交
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
[Dependency(ServiceLifetime.Scoped, AddSelf = true)]
public class UnitOfWorkAttribute : ActionFilterAttribute
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
/// <summary>
/// 初始化一个<see cref="UnitOfWorkAttribute"/>范例的新实例
/// </summary>
public UnitOfWorkAttribute(IServiceProvider serviceProvider)
{
_unitOfWorkManager = serviceProvider.GetService<IUnitOfWorkManager>();
}
/// <summary>
/// 重写要领,完成事件自动提交功用
/// </summary>
/// <param name="context"></param>
public override void OnResultExecuted(ResultExecutedContext context)
{
ScopedDictionary dict = context.HttpContext.RequestServices.GetService<ScopedDictionary>();
AjaxResultType type = AjaxResultType.Success;
string message = null;
if (context.Result is JsonResult result1)
{
if (result1.Value is AjaxResult ajax)
{
type = ajax.Type;
message = ajax.Content;
if (ajax.Successed())
{
_unitOfWorkManager?.Commit();
}
}
}
else if (context.Result is ObjectResult result2)
{
if (result2.Value is AjaxResult ajax)
{
type = ajax.Type;
message = ajax.Content;
if (ajax.Successed())
{
_unitOfWorkManager?.Commit();
}
}
else
{
_unitOfWorkManager?.Commit();
}
}
//一般请求
else if (context.HttpContext.Response.StatusCode >= 400)
{
switch (context.HttpContext.Response.StatusCode)
{
case 401:
type = AjaxResultType.UnAuth;
break;
case 403:
type = AjaxResultType.UnAuth;
break;
case 404:
type = AjaxResultType.UnAuth;
break;
case 423:
type = AjaxResultType.UnAuth;
break;
default:
type = AjaxResultType.Error;
break;
}
}
else
{
type = AjaxResultType.Success;
_unitOfWorkManager?.Commit();
}
if (dict.AuditOperation != null)
{
dict.AuditOperation.ResultType = type;
dict.AuditOperation.Message = message;
}
}
}
如一次请求中触及数据的 新增、更新、删除 操纵时,在 Action 上增添 [ServiceFilter(typeof(UnitOfWorkAttribute))]
,便可完成事件自动提交。
/// <summary>
/// 新增文章
/// </summary>
/// <param name="dtos">新增文章信息</param>
/// <returns>JSON操纵效果</returns>
[HttpPost]
[ModuleInfo]
[ServiceFilter(typeof(UnitOfWorkAttribute))]
[Description("新增")]
public async Task<AjaxResult> Create(PostInputDto[] dtos)
{ }
AjaxReuslt
关于 前后端星散 的项目,前端向后端的请求都是经由过程 application/json
的体式格局来交互的,这就须要在后端对操纵效果举行封装。OSharp供应了AjaxResult
类来承载操纵效果数据
/// <summary>
/// 透露表现Ajax操纵效果
/// </summary>
public class AjaxResult
{
/// <summary>
/// 初始化一个<see cref="AjaxResult"/>范例的新实例
/// </summary>
public AjaxResult()
: this(null)
{ }
/// <summary>
/// 初始化一个<see cref="AjaxResult"/>范例的新实例
/// </summary>
public AjaxResult(string content, AjaxResultType type = AjaxResultType.Success, object data = null)
: this(content, data, type)
{ }
/// <summary>
/// 初始化一个<see cref="AjaxResult"/>范例的新实例
/// </summary>
public AjaxResult(string content, object data, AjaxResultType type = AjaxResultType.Success)
{
Type = type;
Content = content;
Data = data;
}
/// <summary>
/// 猎取或设置 Ajax操纵效果范例
/// </summary>
public AjaxResultType Type { get; set; }
/// <summary>
/// 猎取或设置 音讯内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 猎取或设置 返回数据
/// </summary>
public object Data { get; set; }
/// <summary>
/// 是不是胜利
/// </summary>
public bool Successed()
{
return Type == AjaxResultType.Success;
}
/// <summary>
/// 是不是毛病
/// </summary>
public bool Error()
{
return Type == AjaxResultType.Error;
}
/// <summary>
/// 胜利的AjaxResult
/// </summary>
public static AjaxResult Success(object data = null)
{
return new AjaxResult("操纵实行胜利", AjaxResultType.Success, data);
}
}
个中AjaxResultType
的可选项为:
/// <summary>
/// 透露表现 ajax 操纵效果范例的罗列
/// </summary>
public enum AjaxResultType
{
/// <summary>
/// 音讯效果范例
/// </summary>
Info = 203,
/// <summary>
/// 胜利效果范例
/// </summary>
Success = 200,
/// <summary>
/// 非常效果范例
/// </summary>
Error = 500,
/// <summary>
/// 用户未登录
/// </summary>
UnAuth = 401,
/// <summary>
/// 已登录,但权限缺乏
/// </summary>
Forbidden = 403,
/// <summary>
/// 资本未找到
/// </summary>
NoFound = 404,
/// <summary>
/// 资本被锁定
/// </summary>
Locked = 423
}
营业效劳层的操纵效果OperationResult
,能够很轻松的转换为AjaxResult
/// <summary>
/// 将营业操纵效果转ajax操纵效果
/// </summary>
public static AjaxResult ToAjaxResult<T>(this OperationResult<T> result, Func<T, object> dataFunc = null)
{
string content = result.Message ?? result.ResultType.ToDescription();
AjaxResultType type = result.ResultType.ToAjaxResultType();
object data = dataFunc == null ? result.Data : dataFunc(result.Data);
return new AjaxResult(content, type, data);
}
/// <summary>
/// 将营业操纵效果转ajax操纵效果
/// </summary>
public static AjaxResult ToAjaxResult(this OperationResult result)
{
string content = result.Message ?? result.ResultType.ToDescription();
AjaxResultType type = result.ResultType.ToAjaxResultType();
return new AjaxResult(content, type);
}
经由过程这些扩大要领,能够很简约的完成由OperationResult
到AjaxResult
的转换
public async Task<AjaxResult> Creat(PostInputDto[] dtos)
{
OperationResult result = await _blogsContract.CreatePosts(dtos);
return result.ToAjaxResult();
}
博客模块API完成
下面,我们来综合应用上面界说的基本建设,来完成 博客模块 的API层。
API层的完成代码,将完成以下症结点:
- 界说各实体的 Controller 和 Action,应用
[Description]
特征来声明各个功用点的显现称号 - 应用
[ModuleInfo]
特征来界说API模块的树形构造 - 应用
[DependOnFunction]
来界说各API模块之间的依靠干系 - 在
AdminApiController
基类中,已增添了[RoleLimit]
特征来设置装备摆设一切Admin
地区的API都应用 脚色限定 的接见掌握,如需特别的接见掌握,可在 Action 上零丁设置装备摆设 - 触及实体
增添、更新、删除
操纵的营业,按须要增添[ServiceFilter(typeof(UnitOfWorkAttribute))]
特征来完成事件自动提交
!!! node
API模块对脚色的权限分派,将在背景治理界面中举行权限分派。
博客 - BlogController
依据 <营业模块设想#WebAPI层> 中对博客治理的界说,Blog实体的对外API界说以下表所示:
操纵 | 接见范例 | 操纵脚色 |
---|---|---|
读取 | 脚色接见 | 博客治理员、博主 |
请求开通 | 登录接见 | 已登录未开通博客的用户 |
开通考核 | 脚色接见 | 博客治理员 |
更新 | 脚色接见 | 博客治理员、博主 |
完成代码以下:
[ModuleInfo(Position = "Blogs", PositionName = "博客模块")]
[Description("治理-博客信息")]
public class BlogController : AdminApiController
{
/// <summary>
/// 初始化一个<see cref="BlogController"/>范例的新实例
/// </summary>
public BlogController(IBlogsContract blogsContract,
IFilterService filterService)
{
BlogsContract = blogsContract;
FilterService = filterService;
}
/// <summary>
/// 猎取或设置 数据过滤效劳对象
/// </summary>
protected IFilterService FilterService { get; }
/// <summary>
/// 猎取或设置 博客模块营业左券对象
/// </summary>
protected IBlogsContract BlogsContract { get; }
/// <summary>
/// 读取博客列表信息
/// </summary>
/// <param name="request">页请求信息</param>
/// <returns>博客列表分页信息</returns>
[HttpPost]
[ModuleInfo]
[Description("读取")]
public PageData<BlogOutputDto> Read(PageRequest request)
{
Check.NotNull(request, nameof(request));
Expression<Func<Blog, bool>> predicate = FilterService.GetExpression<Blog>(request.FilterGroup);
var page = BlogsContract.Blogs.ToPage<Blog, BlogOutputDto>(predicate, request.PageCondition);
return page.ToPageData();
}
/// <summary>
/// 请求开通博客
/// </summary>
/// <param name="dto">博客输入DTO</param>
/// <returns>JSON操纵效果</returns>
[HttpPost]
[ModuleInfo]
[DependOnFunction("Read")]
[ServiceFilter(typeof(UnitOfWorkAttribute))]
[Description("请求")]
public async Task<AjaxResult> Apply(BlogInputDto dto)
{
Check.NotNull(dto, nameof(dto));
OperationResult result = await BlogsContract.ApplyForBlog(dto);
return result.ToAjaxResult();
}
/// <summary>
/// 考核博客
/// </summary>
/// <param name="dto">博客输入DTO</param>
/// <returns>JSON操纵效果</returns>
[HttpPost]
[ModuleInfo]
[DependOnFunction("Read")]
[ServiceFilter(typeof(UnitOfWorkAttribute))]
[Description("请求")]
public async Task<AjaxResult> Verify(BlogVerifyDto dto)
{
Check.NotNull(dto, nameof(dto));
OperationResult result = await BlogsContract.VerifyBlog(dto);
return result.ToAjaxResult();
}
/// <summary>
/// 更新博客信息
/// </summary>
/// <param name="dtos">博客信息输入DTO</param>
/// <returns>JSON操纵效果</returns>
[HttpPost]
[ModuleInfo]
[DependOnFunction("Read")]
[ServiceFilter(typeof(UnitOfWorkAttribute))]
[Description("更新")]
public async Task<AjaxResult> Update(BlogInputDto[] dtos)
{
Check.NotNull(dtos, nameof(dtos));
OperationResult result = await BlogsContract.UpdateBlogs(dtos);
return result.ToAjaxResult();
}
}
文章 - PostController
依据 <营业模块设想#WebAPI层> 中对文章治理的界说,Post实体的对外API界说以下表所示:
操纵 | 接见范例 | 操纵脚色 |
---|---|---|
读取 | 脚色接见 | 博客治理员、博主 |
新增 | 脚色接见 | 博主 |
更新 | 脚色接见 | 博客治理员、博主 |
删除 | 脚色接见 | 博客治理员、博主 |
完成代码以下:
[ModuleInfo(Position = "Blogs", PositionName = "博客模块")]
[Description("治理-文章信息")]
public class PostController : AdminApiController
{
/// <summary>
/// 初始化一个<see cref="PostController"/>范例的新实例
/// </summary>
public PostController(IBlogsContract blogsContract,
IFilterService filterService)
{
BlogsContract = blogsContract;
FilterService = filterService;
}
/// <summary>
/// 猎取或设置 数据过滤效劳对象
/// </summary>
protected IFilterService FilterService { get; }
/// <summary>
/// 猎取或设置 博客模块营业左券对象
/// </summary>
protected IBlogsContract BlogsContract { get; }
/// <summary>
/// 读取文章列表信息
/// </summary>
/// <param name="request">页请求信息</param>
/// <returns>文章列表分页信息</returns>
[HttpPost]
[ModuleInfo]
[Description("读取")]
public virtual PageData<PostOutputDto> Read(PageRequest request)
{
Check.NotNull(request, nameof(request));
Expression<Func<Post, bool>> predicate = FilterService.GetExpression<Post>(request.FilterGroup);
var page = BlogsContract.Posts.ToPage<Post, PostOutputDto>(predicate, request.PageCondition);
return page.ToPageData();
}
/// <summary>
/// 新增文章信息
/// </summary>
/// <param name="dtos">文章信息输入DTO</param>
/// <returns>JSON操纵效果</returns>
[HttpPost]
[ModuleInfo]
[DependOnFunction("Read")]
[ServiceFilter(typeof(UnitOfWorkAttribute))]
[Description("新增")]
public virtual async Task<AjaxResult> Create(PostInputDto[] dtos)
{
Check.NotNull(dtos, nameof(dtos));
OperationResult result = await BlogsContract.CreatePosts(dtos);
return result.ToAjaxResult();
}
/// <summary>
/// 更新文章信息
/// </summary>
/// <param name="dtos">文章信息输入DTO</param>
/// <returns>JSON操纵效果</returns>
[HttpPost]
[ModuleInfo]
[DependOnFunction("Read")]
[ServiceFilter(typeof(UnitOfWorkAttribute))]
[Description("更新")]
public virtual async Task<AjaxResult> Update(PostInputDto[] dtos)
{
Check.NotNull(dtos, nameof(dtos));
OperationResult result = await BlogsContract.UpdatePosts(dtos);
return result.ToAjaxResult();
}
/// <summary>
/// 删除文章信息
/// </summary>
/// <param name="ids">文章信息编号</param>
/// <returns>JSON操纵效果</returns>
[HttpPost]
[ModuleInfo]
[DependOnFunction("Read")]
[ServiceFilter(typeof(UnitOfWorkAttribute))]
[Description("删除")]
public virtual async Task<AjaxResult> Delete(int[] ids)
{
Check.NotNull(ids, nameof(ids));
OperationResult result = await BlogsContract.DeletePosts(ids);
return result.ToAjaxResult();
}
}
至此,博客模块的 API层代码 完成终了。
API数据展现
运转Liuliu.Blogs
项目的后端工程Liuliu.Blogs.Web
,框架初始化时将经由过程 反射读取API层代码构造,举行博客模块的 API模块Module
- API功用点Function
的数据初始化,并分派好 依靠干系,功用点的 接见掌握 等束缚。
Swagger检察数据
在SwaggerUI中,我们能够看到天生的 API模块
博客 - Blog
文章 - Post
背景治理检察数据
运转前端的 Angular 工程,我们能够在背景治理的 权限平安/模块治理 中,可看到 博客模块
的模块数据以及模块分派的功用点信息
数据库检察数据
翻开数据库治理工具,能够看到 Module 和 Function 两个表的相干数据
数据库中的 API模块Module
数据库中的 API功用点Function
博客模块受权
相干脚色和用户
博客模块相干脚色
依据 <营业模块设想#WebAPI层> 中对权限掌握的界说,我们须要建立两个相干脚色
- 博主:可请求博客,更新本身的博客,对本身的文章举行新增、更新、删除操纵
- 博客治理员:可审批、更新、删除一切博客,对一切文章举行更新、删除操纵
新增的两个脚色以下:
称号 | 备注 | 治理脚色 | 默许 | 锁定 |
---|---|---|---|---|
博客治理员 | 博客治理员脚色 | 是 | 否 | 否 |
博主 | 博客主人脚色 | 否 | 否 | 否 |
注册两个测试用户,并给用户分派脚色
新增测试用户以下:
用户名 | 用户昵称 | 分派脚色 |
---|---|---|
123202901@qq.com | 博客治理员测试 | 博客治理员 |
31529019@qq.com | 博主测试01 | 博主 |
2048949401@qq.com | 博主测试02 | 博主 |
功用权限
给脚色分派API模块
API模块Module
对应的是后端的API模块,将Module分派给脚色Role
,响应的Role即具有Module的一切功用点Function
给
博客治理员
脚色分派功用权限给
博主
脚色分派功用权限
功用权限预览
分派好以后,具有特定脚色的用户,便具有模块所带来的功用点权限
博客治理员用户功用权限
- 博主用户功用权限
测试博主01
测试博主02
数据权限
OSharp框架内默许供应 脚色 - 实体 配对的数据权限指派。
博客治理员
关于博客治理员
脚色,博客治理员能治理 博客Blog
和 文章Post
的一切数据,没有数据权限的束缚请求。
博主
关于博主
脚色,博主只能检察并治理 本身的 博客与文章,有数据权限的束缚请求。对博主的数据权限束缚以下:
对博客的读取、更新操纵限定
UserId = @以后用户
对文章的读取、更新、删除操纵限定
UserId = @以后用户
云云,对博客模块的数据权限束缚分派终了。
鄙人一节中,我们将完美前端项目,增添博客模块的前端完成,你将看到一个完全的博客模块完成。
Comment here is closed