甚么是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);
}

经由过程这些扩大要领,能够很简约的完成由OperationResultAjaxResult的转换

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 = @以后用户

云云,对博客模块的数据权限束缚分派终了。

鄙人一节中,我们将完美前端项目,增添博客模块的前端完成,你将看到一个完全的博客模块完成。

Last modification:March 25, 2020
如果觉得我的文章对你有用,请随意赞赏