这两天遇到一个应用场景,需要对内网调用的部分 web api 进行安全保护,只允许请求头账户包含指定 key 的客户端进行调用。在网上找到一篇英文博文 ASP.NET Core - Protect your API with API Keys,该文中的代码完美基于 ASP.NET Core 内置的鉴权(Authentication) 与授权(Authorization)机制解决了这个问题,于是站在巨人的肩上自己实现了一遍,在这篇随笔中做个记录。

ASP.NET Core Authentication 与 Authorization 实现的开源代码在 https://github.com/aspnet/AspNetCore/tree/master/src/Security

使用 API Key 对私有 Web API 进行保护,实际就是通过自定义的 AuthenticationHandler 对 ASP.NET Core Authentication 的鉴权能力进行扩展,具体实现分4步。

1)实现配角(配置选项)ApiKeyAuthenticationOptions

public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions
{
public const string DefaultScheme = "ApiKey";
public string Scheme { get; set; } = DefaultScheme;
public string AuthenticationType { get; set; } = DefaultScheme;
}

这里的示例程序很简单,选项只用于定义 DefaultScheme 。

2)实现主角 ApiKeyAuthenticationHandler

public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions>
{
private const string HEADER_NAME = "X-Api-Key";
private readonly (string Owner, string Key)[] _apiKeys = new[] { ("test", "xxx123yyy456zzz") };
private readonly ApiKeyAuthenticationOptions _options; public ApiKeyAuthenticationHandler(
IOptionsMonitor<ApiKeyAuthenticationOptions> options,
ILoggerFactory logger,
UrlEncoder Encoder,
ISystemClock clock) : base(options, logger, Encoder, clock)
{
_options = options.CurrentValue;
} protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var providedApiKey = Context.Request.Headers[HEADER_NAME].FirstOrDefault();
if (string.IsNullOrWhiteSpace(providedApiKey))
{
return AuthenticateResult.NoResult();
} var apiKey = _apiKeys.FirstOrDefault(k => k.Key == providedApiKey);
if (apiKey != default)
{
var claims = new[]
{
new Claim(ClaimTypes.Name, apiKey.Owner)
};
var identity = new ClaimsIdentity(claims, authenticationType: _options.AuthenticationType);
var identities = new List<ClaimsIdentity> { identity };
var principal = new ClaimsPrincipal(identities);
var ticket = new AuthenticationTicket(principal, authenticationScheme: _options.Scheme); await Task.CompletedTask;
return AuthenticateResult.Success(ticket);
} return AuthenticateResult.Fail("Invalid API Key provided.");
}
}

在 override 方法 HandleAuthenticateAsync 中实现基于 API Key 对私有 Web API 进行保护的鉴权逻辑,根据客户端请求头进行验证,如果是合法请求,就发一个 ticket 。有了这张门票, 如果只要有门票就能通过(比如加了[Authorize]声明), 没有其他授权要求,Authorization 就会直接放行。

3)实现跑龙套的 AuthenticationBuilderExtensions 扩展方法

public static class AuthenticationBuilderExtensions
{
public static AuthenticationBuilder AddApiKeySupport(this AuthenticationBuilder authenticationBuilder)
{
return authenticationBuilder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(
ApiKeyAuthenticationOptions.DefaultScheme,
options => { });
} public static AuthenticationBuilder AddApiKeySupport(this AuthenticationBuilder authenticationBuilder,
Action<ApiKeyAuthenticationOptions> options)
{
return authenticationBuilder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(
ApiKeyAuthenticationOptions.DefaultScheme,
options);
}
}

这个扩展方法只是为了方便在 Startup 中添加 ApiKeyAuthenticationHandler 。

4)开始演戏

Startup.ConfigureServices 中配置 Authentication

services.AddAuthentication(options =>
{
options.DefaultScheme = ApiKeyAuthenticationOptions.DefaultScheme;
options.DefaultChallengeScheme = ApiKeyAuthenticationOptions.DefaultScheme;
}).AddApiKeySupport();

Startup.Configure 中添加 Authentication 与 Authorization 中间件(注:一定要放在 app.UseRouting 之后)

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});

对需要保护的 web api 添加 [Authorize] 声明

[Authorize]
public async Task<bool> ProtectedAction()
{
//...
}

搞定。

ASP.NET Core 中基于 API Key 对私有 Web API 进行保护的更多相关文章

  1. 【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

    HTTP is not just for serving up web pages. It's also a powerful platform for building APIs that expo ...

  2. [转]【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

    本文转自:https://www.cnblogs.com/inday/p/6288707.html HTTP is not just for serving up web pages. It’s al ...

  3. 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(二)-- Web Api Demo

    在上一篇里,我已经建立了一个简单的Web-Demo应用程序.这一篇将记录将此Demo程序改造成一个Web Api应用程序. 一.添加ASP.NET Core MVC包 1. 在project.json ...

  4. ASP.NET Core 中基于工厂的中间件激活

    IMiddlewareFactory/IMiddleware 是中间件激活的扩展点. UseMiddleware 扩展方法检查中间件的已注册类型是否实现 IMiddleware. 如果是,则使用在容器 ...

  5. 在ASP.NET Core中添加的Cookie如果含有特殊字符,会被自动转义

    我们知道在Cookie中有些字符是特殊字符,这些字符是不能出现在Cookie的键值中的. 比如"="是Cookie中用来分隔键和值的特殊字符,例如:Key01=Value01,表示 ...

  6. ASP.NET Core中的OWASP Top 10 十大风险-跨站点脚本攻击 (XSS)

    不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: https://dotnetcoretutorials.com/201 ...

  7. C# 嵌入dll 动软代码生成器基础使用 系统缓存全解析 .NET开发中的事务处理大比拼 C#之数据类型学习 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持 基于EF Core的Code First模式的DotNetCore快速开发框架 【懒人有道】在asp.net core中实现程序集注入

    C# 嵌入dll   在很多时候我们在生成C#exe文件时,如果在工程里调用了dll文件时,那么如果不加以处理的话在生成的exe文件运行时需要连同这个dll一起转移,相比于一个单独干净的exe,这种形 ...

  8. 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获

    项目开发中的一些注意事项以及技巧总结   1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...

  9. 在ASP.NET Core中创建基于Quartz.NET托管服务轻松实现作业调度

    在这篇文章中,我将介绍如何使用ASP.NET Core托管服务运行Quartz.NET作业.这样的好处是我们可以在应用程序启动和停止时很方便的来控制我们的Job的运行状态.接下来我将演示如何创建一个简 ...

随机推荐

  1. Linux下的find命令2

    :续linux下的find命令 Linux/Unix下非常有用的find命令的用法 功能简述:find(查找)主要沿着文件层次(目录)结构依次向下遍历,匹配符合条件的文件,可以附带执行相应的操作选项, ...

  2. CodeForces - 1265D(贪心+暴力)

    题意 https://vjudge.net/problem/CodeForces-1265D a个0,b个1,c个2,d个3,问是否存在一种排列方案使得任意相邻两数之差==1 思路 分类讨论太麻烦了, ...

  3. Python 获取MD5加密值

    Python 获取MD5加密值方法封装 import hashlib def get_md5(s): """获取MD5加密值 :param s: 需要加密的字符串 :re ...

  4. Spring Boot 2 快速教程:WebFlux 集成 Thymeleaf(五)

    号外:为读者持续整理了几份最新教程,覆盖了 Spring Boot.Spring Cloud.微服务架构等PDF.获取方式:关注右侧公众号"泥瓦匠BYSocket",来领取吧! 摘 ...

  5. python Windows环境下文件路径问题

    转自:http://blog.sina.com.cn/s/blog_5ee7254801013zu7.html 在python程序里面我们经常需要对文件进行操作,Windows下的文件目录路径使用反斜 ...

  6. Linux介绍以及VMware和Centos的安装

    一. Linux介绍 1 Linux诞生的故事 Unix篇: 为了进一步强化大型主机的功能,让主机的资源可以提供更多的使用者来利用,所以在1964年, 由AT&A公司的贝尔实验室(Bell). ...

  7. Add an Action with Option Selection 添加具有选项选择的按钮

    In this lesson, you will learn how to create an Action with support for option selection. A new View ...

  8. javascript模块化开发(二)

    模块化开发(一) ES6模块化 详解 ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict". 顶层的this指向undefined,即不应该在顶层代码 ...

  9. Python3 进程、线程和协程

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 进程.线程和协程的对比 1.定义对比 进程:是系统进行资源分配的基本单位,每启动一个进程,操作系统都需要为其分配运 ...

  10. PHP 7.0 7.3 (Unix) - 'gc' Disable Functions Bypass

    <?php # PHP 7.0-7.3 disable_functions bypass PoC (*nix only) # # Bug: https://bugs.php.net/bug.ph ...