asp.net core 自定义 Policy 替换 AllowAnonymous 的行为
2019-11-20 23:12
1556 查看
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[练习10]-Identity-自定义Policy
- ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)
- 学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一个服务器感受一下管道是如何监听、接收和响应请求的
- ASP.NET Core中自定义路由约束的实现
- ASP.NET Core的身份认证框架IdentityServer4--(5)自定义用户登录(使用官网提供的UI)
- ASP.NET Core 中文文档 第四章 MVC(3.6.2 )自定义标签辅助类(Tag Helpers)
- [Asp.net core]自定义中间件
- ASP.NET Core 1.0 静态文件、路由、自定义中间件、身份验证简介
- Asp.Net Core 自定义设置Http缓存处理
- ASP.NET Core中显示自定义错误页面-增强版
- ASP.NET Core开发期间部署到IIS自定义主机域名并附加到进程调试
- ASP.NET Core中使用IOC三部曲(三.采用替换后的Autofac来实现AOP拦截)
- ASP.NET Core中使用IOC三部曲(三.采用替换后的Autofac来实现AOP拦截)
- ASP.NET CORE 学习之自定义异常处理
- asp.net core利用DI实现自定义用户系统,脱离ControllerBase.User
- 【ASP.NET Core】MVC中自定义视图的查找位置
- ASP.NET Core 在 Swagger UI 中显示自定义的 Header Token
- asp.net core 自定义401和异常显示内容(JWT认证、Cookie Base认证失败显示内容)
- ASP.NET Core - 实现自定义WebApi模型验证
- 在ASP.NET Core中实现自定义验证特性(Custom Validation Attribute)