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. Spring Cloud OAuth2 实现用户认证及单点登录

    文章较长,建议推荐,建议转发,建议收藏,建议关注公众号哈. OAuth 2 有四种授权模式,分别是授权码模式(authorization code).简化模式(implicit).密码模式(resou ...

  2. [HDU5001]Walk

    Problem Description I used to think I could be anything, but now I know that I couldn't do anything. ...

  3. gedit 外部工具——快捷运行

    可快捷编译运行一些代码,适合新手使用. 配置如下. 快捷键:F5 保存:当前文档 输入:无 输出:无 使用范围:所有文档,所有语言 脚本如下. #!/bin/sh #author: srczhang# ...

  4. 修改配置文件application.properties

    附录A.常用应用程序属性 可以在application.properties文件内部application.yml,文件内部或命令行开关中指定各种属性.本附录提供了常见Spring Boot属性的列表 ...

  5. 玩转ArduinoJson库 V6版本

    1.前言     前面,博主已经讲解了ArduinoJson库的V5版本.为了节省时间以及不讨论重复内容,博主建议读者先去阅读一下 玩转ArduinoJson库 V5版本 .重点了解几个东西: JSO ...

  6. IDEA+docker,进行远程漏洞调试(weblogic)

    用于学习java漏洞debug. 以weblogic为例. cve-2017-10271 weblogic:10.3.6 环境搭建 拿docker为例 https://github.com/vulhu ...

  7. 函数进阶(二) day13

    目录 昨日内容 闭包函数 装饰器 二层装饰器 装饰器模板 三层装饰器 今日内容 迭代器 可迭代对象 迭代器对象 for循环原理(迭代循环) 三元表达式 列表推导式 字典生成式 生成器 yield关键字 ...

  8. Leetcode Tags(5)Hash Table

    一.500. Keyboard Row 给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词. 输入: ["Hello", "Alaska", &q ...

  9. Leetcode Tags(3)String(TODO)

    一.Easy 696 Count Binary Substrings Input: "00110011" Output: 6 Explanation: There are 6 su ...

  10. Mysql数据库(十)MySQL性能优化

    一.优化概述 为了提高MySQL数据库的性能,不要进行一系列的优化措施.如果MySQL数据库需要进行大量的查询操作,那么就需要对查询语句进行优化.对于耗费时间的查询语句进行优化,可以提高整体地查询速度 ...