asp.net core 自定义 Policy 替换 AllowAnonymous 的行为

Intro

最近对我们的服务进行了改造,原本内部服务在内部可以匿名调用,现在增加了限制,通过 identity server 来管理 api 和 client,网关和需要访问api的客户端或api服务相互调用通过 client_credencial 的方式来调用,这样一来我们可以清晰知道哪些 api 服务会被哪些 api/client 所调用,而且安全性来说更好。

为了保持后端服务的代码更好的兼容性,希望能够实现相同的代码通过在 Startup 里不同的配置实现不同的 Authorization 逻辑,原来我们的服务的 Authorize 都是以 Authorize("policyName") 的形式来写的,这样一来我们只需要修改这个 Policy 的授权配置就可以了。对于 AllowAnonymous 就希望可以通过一种类似的方式来实现,通过自定义一个 Policy 来实现自己的逻辑

实现方式

将 action 上的 AllowAnonymous 替换为 Authorize("policyName"),在没有设置 Authorize 的 controller 上增加 Authorize("policyName")

public class AllowAnonymousPolicyTransformer : IApplicationModelConvention
{
private readonly string _policyName; public AllowAnonymousPolicyTransformer() : this("anonymous")
{
} public AllowAnonymousPolicyTransformer(string policyName) => _policyName = policyName; public void Apply(ApplicationModel application)
{
foreach (var controllerModel in application.Controllers)
{
if (controllerModel.Filters.Any(_ => _.GetType() == typeof(AuthorizeFilter)))
{
foreach (var actionModel in controllerModel.Actions)
{
if (actionModel.Filters.Any(_ => _.GetType() == typeof(AllowAnonymousFilter)))
{
var allowAnonymousFilter = actionModel.Filters.First(_ => _.GetType() == typeof(AllowAnonymousFilter));
actionModel.Filters.Remove(allowAnonymousFilter);
actionModel.Filters.Add(new AuthorizeFilter(_policyName));
}
}
}
else
{
if (controllerModel.Filters.Any(_ => _.GetType() == typeof(AllowAnonymousFilter)))
{
var allowAnonymousFilter = controllerModel.Filters.First(_ => _.GetType() == typeof(AllowAnonymousFilter));
controllerModel.Filters.Remove(allowAnonymousFilter);
}
controllerModel.Filters.Add(new AuthorizeFilter(_policyName));
}
}
}
} public static class MvcBuilderExtensions
{
public static IMvcBuilder AddAnonymousPolicyTransformer(this IMvcBuilder builder)
{
builder.Services.Configure<MvcOptions>(options =>
{
options.Conventions.Insert(0, new AllowAnonymousPolicyTransformer());
});
return builder;
} public static IMvcBuilder AddAnonymousPolicyTransformer(this IMvcBuilder builder, string policyName)
{
builder.Services.Configure<MvcOptions>(options =>
{
options.Conventions.Insert(0, new AllowAnonymousPolicyTransformer(policyName));
});
return builder;
}
}

controller 中的代码:

[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly ILogger _logger; public ValuesController(ILogger<ValuesController> logger)
{
_logger = logger;
} // GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
var msg = $"IsAuthenticated: {User.Identity.IsAuthenticated} ,UserName: {User.Identity.Name}";
_logger.LogInformation(msg);
return new string[] { msg };
} // GET api/values/5
[Authorize]
[HttpGet("{id:int}")]
public ActionResult<string> Get(int id)
{
return "value";
}
// ...
}

Startup 中 ConfigureServices 配置:

var anonymousPolicyName = "anonymous";

services.AddAuthorization(options =>
{
options.AddPolicy(anonymousPolicyName, builder => builder.RequireAssertion(context => context.User.Identity.IsAuthenticated)); options.DefaultPolicy = new AuthorizationPolicyBuilder(HeaderAuthenticationDefaults.AuthenticationSchema)
.RequireAuthenticatedUser()
.RequireAssertion(context => context.User.GetUserId<int>() > 0)
.Build();
}); services.AddMvc(options =>
{
options.Conventions.Add(new ApiControllerVersionConvention());
})
.AddAnonymousPolicyTransformer(anonymousPolicyName)
;

实现效果

访问原来的匿名接口

userId 为0访问原来的匿名接口

userId 大于0访问原来的匿名接口

userId 为0访问需要登录的接口

userId 大于0访问需要登录的接口

More

注:按照上面的做法已经可以做到自定义 policy 代替 AllowAnonymous 的行为,但是原来返回的401,现在可能返回到就是 403 了

Reference

asp.net core 自定义 Policy 替换 AllowAnonymous 的行为的更多相关文章

  1. asp.net core 自定义认证方式--请求头认证

    asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...

  2. 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?

    原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...

  3. asp.net core自定义端口

    asp.net Core 自定义端口 官方文档 aspnet内库源码: https://github.com/aspnet dotnet系统内库源码:https://github.com/dotnet ...

  4. asp.net core 自定义异常处理中间件

    asp.net core 自定义异常处理中间件 Intro 在 asp.net core 中全局异常处理,有时候可能不能满足我们的需要,可能就需要自己自定义一个中间件处理了,最近遇到一个问题,有一些异 ...

  5. asp.net core 自定义基于 HttpContext 的 Serilog Enricher

    asp.net core 自定义基于 HttpContext 的 Serilog Enricher Intro 通过 HttpContext 我们可以拿到很多有用的信息,比如 Path/QuerySt ...

  6. Asp.net core自定义依赖注入容器,替换自带容器

    依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...

  7. gRPC asp.net core自定义策略认证

    在GitHub上有个项目,本来是作为自己研究学习.net core的Demo,没想到很多同学在看,还给了很多星,所以觉得应该升成3.0,整理一下,写成博分享给学习.net core的同学们. 项目名称 ...

  8. ASP.NET CORE 自定义视图组件(ViewComponent)注意事项

    *红色字体为固定命名,蓝色为一般命名规则,黄色为ASP.NET CORE 默认查找文件名 概要:1.简单ViewComponent的用法 2.ViewComponent控制器返回值  3.注意事项 1 ...

  9. 解决 ASP.NET Core 自定义错误页面对 Middleware 异常无效的问题

    我们基于 Razor Class Library 实现了自定义错误页面的公用类库(详见之前的随笔),但是在实际使用时发现如果在 middleware 中发生了异常,则不能显示自定义错误页面,而是返回默 ...

随机推荐

  1. 代码审计-(Ear Music).任意文件下载漏洞

    0x01 代码分析 后台地址:192.168.5.176/admin.php admin admin 安装后的界面 在后台发布了一首新歌后,前台点进去到一个“下载LRC歌词”功能点的时候发现是使用re ...

  2. [JOYOI1326] 剑人合一

    题目限制 时间限制 内存限制 评测方式 题目来源 1000ms 131072KiB 标准比较器 Local 题目描述 他们飘呀飘,飘呀飘,飘呀飘,飘呀飘~~~经过七七八十一天的漂泊,残雪.夏夜和水手2 ...

  3. 将JSON反序列化为指定的.NET类型

    前言: 关于将JSON格式数据反序列化为指定的.NET类型数据常见的场景就是,关于网络请求获取请求成功的响应数据.本篇主要讲的的是如何通过使用Newtonsoft.Json中的JsonConvert. ...

  4. css定位 双飞翼

    <!doctype html><html><head><meta charset="utf-8"><title>双飞翼& ...

  5. java 连续数字数组分组

    问题: 1. 将Lis list = Arrays.asList(1,2,3,5,8,9,10), 拆分成 [1,2,3] .[5]. [8,9,10] , 2. 再传入一个数字 9, 将匹配数字9的 ...

  6. 有Bug?你的代码神兽选对了吗

    传说每一个优秀的程序员都有自己专属的镇码神兽 通过 工具网址 http://www.makepic.net/Tool/Image2ascii.html 将自己喜欢的神兽图片转成文本, 可以选择不同的分 ...

  7. Python3.8更新特性

    Python 3.8.0稳定版 部分新特性: • PEP 572,赋值+表达式 :=可以将一个表达式或者一个 if (n := len(a)) > 10:#表达式仍然用,赋值也放一起,后面不用多 ...

  8. 正则表达式和python中的re模块

    ---恢复内容开始--- 常用的正则匹配规则 元字符 量词 字符组 字符集 转义符 贪婪匹配 re模块使用正则表达式 实例引入(是否使用re模块和正则表达式的区别) # 不使用正则表达式 phone_ ...

  9. 学习笔记13_第三方js控件&EasyUI使用

    第三方UI包使用思路: 1.先映入各种JS包,包含JS版本包,第三方CSS包,第三方主JS包,第三方语言包. 2.确定要做什么,是对话框还是表格.3.根据Demo和目的,在<body>内, ...

  10. 学习笔记12JS异步请求

    *一般用JS来监听按钮事件,都应该先监听页面OnLoad事件. *Js写在哪里,就会在页面解析到哪里执行. 异步请求:所谓异步请求,就是使用JS来监听按钮点击事件,并且发送请求,等到回复后,再使用JS ...