首页 > 其他分享 >ABP VNext添加全局认证(如何继承AuthorizeFilter)

ABP VNext添加全局认证(如何继承AuthorizeFilter)

时间:2023-07-25 14:46:12浏览次数:48  
标签:VNext return AuthorizeFilter OnAuthorizationAsync ABP api context public

前言

目前公司采用的开发框架是ABP VNext微服务框架

最近突然发现一个问题,ABP中如果控制器或服务层没有加 Authorize特性的话,则不会走身份认证,且不会认证Token

如图:

 

但是项目已开发大半,一个个去补Authorize特性,工作量比较大,也容易产生遗漏

就想着以前做单体应用的时候,有个全局添加特性的方法,也就是如下代码:

Services.AddMvc(setupAction =>
{
   setupAction.Filters.Add<AuthorizeFilter>();
});

本以为这样就万事大吉了,没想到还有坑在里面..

我们都知道,ABP提供了服务间的动态API通讯功能,它的原理是先获取对应服务的描述,然后通过描述来访问对应的服务节点,

也就是 api/abp/api-definition 这个描述JSON

我们用以上的代码添加了全局授权之后会发现api-definition也被权限管控了,由于api-definition是由ABP框架自动生成的,我们也无法在这个终结点上添加类似  AllowAnonymous 的过滤特性

 

正文

 

那么应该如何解决这个问题呢?

首先想到的就是实现自己的授权特性,只需要继承 IAsyncAuthorizationFilter,即可

但是如果采用自己的AuthorizationFilter,则需要重写整个 OnAuthorizationAsync 事件.

ABP提供了角色之类的授权信息就都需要自行重写.

后来想到,可以继承AuthorizeFilter ,添加我们想要的过滤之后直接执行父类的方法,说干就干,我们继承AuthorizeFilter ,代码实现如下:

    public class AbpAuthorizeFilter : AuthorizeFilter
    {

        public AbpAuthorizeFilter()
            : base()
        {
        }

        public override Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            //过滤动态API
            if (context.HttpContext.Request.Path.Value.EndsWith("/api-definition"))
            {
                return Task.CompletedTask;
            }
            return base.OnAuthorizationAsync(context);
        }

    }

 

可是当我们信心满满的把这个拦截器注入之后,会发现整个授权管道,压根就不走自己的这个重写方法.

找了很多资料,最终在官方的issues中找到了类似的疑问,Overrided OnAuthorizationAsync function from AuthorizeFilter can't work in customer class. · Issue #30025 · dotnet/aspnetcore (github.com)

是因为在.NET 5.0 之后,AuthorizeFilter继承了 IFilterFactory,所以在生成实例的时候其实是来自于IFilterFactory的CreateInstance方法, 我们没有重写这个方法,所以一直产生的还是AuthorizeFilter 实例

我们修改代码如下:

    public class AbpAuthorizeFilter2 : AuthorizeFilter
    {

        public AbpAuthorizeFilter2()
            : base()
        {
        }

        public override Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            //过滤动态API
            if (context.HttpContext.Request.Path.Value.EndsWith("/api-definition"))
            {
                return Task.CompletedTask;
            }
            return base.OnAuthorizationAsync(context);
        }

        IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
        {
            return this;
        }
    }

  

运行后发现,在执行到这个拦截器的时候,就会报错,提示PolicyProvider 不能为空.  这就很纳闷了,最终选择去查看一下AuthorizeFilter的源码,aspnetcore/src/Mvc/Mvc.Core/src/Authorization/AuthorizeFilter.cs at 1bda10b33b6cc6f3bbaceabbadb4ddd18ca6e68e · dotnet/aspnetcore (github.com)

我们发现他这个PolicyProvider对象来自于IOC容器,且在CreateInstance方法中判断了这个类是否为空,如果为空则返回基类自己,代码如下:

IFilterMetadata IFilterFactory.CreateInstance(IServiceProvider serviceProvider)
{
        if (Policy != null || PolicyProvider != null)
        {
            // The filter is fully constructed. Use the current instance to authorize.
            return this;
        }

        Debug.Assert(AuthorizeData != null);
        var policyProvider = serviceProvider.GetRequiredService<IAuthorizationPolicyProvider>();
        return AuthorizationApplicationModelProvider.GetFilter(policyProvider, AuthorizeData);
 }

 

那我们就好办了,直接从IOC容器中拿到IAuthorizationPolicyProvider这个实现类,提供给基类即可,我们修改代码如下:

    public class AbpAuthorizeFilter:AuthorizeFilter 
    {

        public AbpAuthorizeFilter(IServiceProvider serviceProvider)
            : base(policyProvider: serviceProvider.GetRequiredService<IAuthorizationPolicyProvider>(), authorizeData: new[] { new AuthorizeAttribute() })
        {
        }
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            OnAuthorizationAsync(context);
        }

        public override Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            //过滤动态API
            if (context.HttpContext.Request.Path.Value.EndsWith("/api-definition"))
            {
                return Task.CompletedTask;
            }
            return base.OnAuthorizationAsync(context);
        }

    }

然后修改HostModule中全局授权的方法如下(.NETCORE 是Startup)

context.Services.AddMvc(setupAction =>
{
  //添加自定义的全局拦截器
  setupAction.Filters.Add<AbpAuthorizeFilter>();

});

 

至此,我们就完成了过滤abp的描述控制器的工作.

后记

碰到奇葩问题,多看看官方源码还是有好处的,有些实现并不是想当然的东西,还是需要实践

标签:VNext,return,AuthorizeFilter,OnAuthorizationAsync,ABP,api,context,public
From: https://www.cnblogs.com/GuZhenYin/p/17579808.html

相关文章

  • 利用Abp过滤器实现业务数据“回收站”功能
    目录原理创建过滤器使用过滤器查询删除恢复新版Volo.Abp的控制器配置 原理回收站是当用户删除一条记录时,不是直接从数据库中删除,而是将其放入“回收站”,以便用户可以在需要时恢复数据。在Abp框架中,若实体实现了ISoftDelete,则将实体标记为删除时不是物理删除,而......
  • AbpVnext系列<二> 简化项目并启动项目
    一、卸载掉一些暂时用不到的项目如下图红线划掉所示。让项目结构更符合最简化的要求。二、卸载掉删HttpApi.Host引用里的相关EF包,这里不再让api直接操作数据库的相关操作。如果用codefirst的话那就独立一个种子项目。三、修改一下启动项目,讲启动项目改成,并启动。 四、启动......
  • abp-vnext-pro 实战(一,如何增加菜单项)
    1.在前端的vbenadmin目录新增菜单直接在src/router/routes/modules内新增一个模块文件即可。不需要手动引入,放在src/router/routes/modules内的文件会自动被加载。importtype{AppRouteModule}from'/@/router/types';import{LAYOUT}from'/@/router/constant';......
  • ABP Framework - 后台服务
    后台服务在ABPFramework中,后台分为作业和工作者,他们的不同点为:作业持久性的任务,可放在队列中执行。失败后会继续重试工作者在后台运行的独立线程定期运行后台作业依赖包:Volo.Abp.BackgroundJobs.Abstraction创建后台作业后台作业是通过实现IBackgroundJob<TAr......
  • 利用Abp过滤器实现业务数据“回收站”功能
    @目录原理创建过滤器使用过滤器查询删除恢复原理回收站是当用户删除一条记录时,不是直接从数据库中删除,而是将其放入“回收站”,以便用户可以在需要时恢复数据。在Abp框架中,若实体实现了ISoftDelete,则将实体标记为删除时不是物理删除,而是“软删除”publicinterfaceISoftDelete......
  • ABP-配置设置
    配置设置ABP遵循的是约定大于配置,作为约定的内容需要在应用程序中进行设置。定义设置在设置之前需要先定义他,由于ABP是模块化的,不同模块都可以拥有自己独立的设置参数,只需要在类中派生SettingDefinitionProvider类//ABP会自动发现并和注册设置的定义publicclassStudentSet......
  • Abp Blazor WebAssembly - Polymorphic DTO Deserialization using System.Text.Json
    @@abp4.0dtojobject https://stackoverflow.com/questions/70032776/abp-blazor-webassembly-polymorphic-dto-deserialization-using-system-text-json1AbpFrameworkversion:5.0.0-beta2,UI:BlazorWebAssemblyI'mattemptingtoimplementpolymo......
  • Abp Framework手动实践
    上一章节有很大一部分是使用默认的CRID进行操作的,本章节将手动进行各层的编写,本次以Student为模块进行开发。领域层实体在***.Domain项目中创建Student文件夹,并在文件夹中创建Student的实体类,该实体类继承FullAuditedAggregateRoot<Guid>类,主键为Guid类型。Student共有三个属......
  • ABP Framework
    ABPFramework模板运行安装并下载模板安装ABPCLI,第一步是安装ABPCLIdotnettoolinstall-gVolo.Abp.Cli然后使用abpnew命令在空文件夹中创建新解决方案://项目名称为AbpBlazor.BookStore//UI模板使用BlazorServer模式,默认为MVC//数据库使用MySql(EFframework)......
  • ABP说搞就搞系列——模块热插拔实现(二)
    Orchard是一个开源的、基于ASP.NETMVC的CMS(内容管理系统)平台,它支持模块化和主题化,允许用户方便地扩展和定制其功能。Orchard的模块热插拔主要依赖于以下几个关键部分:模块文件结构:每个模块都被放在一个单独的文件夹中,并且有一个预定义的文件和文件夹结构,这样Orchard就可以知道......