ASP.NET Core实现 随处可见的基本身份认证
概览
在HTTP中,基本认证(Basic access authentication,简称BA认证)是一种用来允许网页浏览器或其他客户端程序在请求资源时提供用户名和口令形式的身份凭证的一种登录验证方式,不要求cookie,session identifier、login page等标记或载体。
优点:基本上所有流行的网页浏览器都支持BA认证。
缺点:明文传输密钥和口令(容易被拦截); 没有对服务器返回的信息提供保护。
https://en.wikipedia.org/wiki/Basic_access_authentication
特征
基本身份认证原理不保证传输凭证的安全性,他们仅仅只是被based64编码,并没有encrypted或者hashed。
一般部署在可信任网络,在公开网络中部署BA认证通常要与https结合使用。
因为基本身份认证字段在HTTP Header 中发送,所以web browser需要在一个合理的时间内缓存凭据,缓存策略因浏览器不同而异,IE默认缓存15 分钟。 HTTP不会为客户端提供一个logout方法,但是有很多方法在浏览器中可以清除缓存凭据。
<script>document.execCommand('ClearAuthenticationCache');</script>
IIS-WebSite-身份认证:

BA认证的标准协议
BA认证协议的实施主要依靠约定的请求头/响应头, 典型的浏览器和服务器的BA认证流程,包含以下步骤:
1.浏览器请求一个需要身份认证的页面,但是没有提供用户名和口令。这通常是用户在地址栏输入一个URL,或是打开了一个指向该页面的链接。
2.服务端响应一个401应答码,并提供一个认证域。
HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="180.76.176.244"
3.接到应答后,浏览器显示该认证域并提示输入用户名和口令。此时用户可以选择确定或取消。
4.用户输入了用户名和口令后,浏览器会在原请求方式上增加认证消息头Authorization:{base64encode(username+":"+password)},然后重新发送再次尝试。
// 下面的例子显示:认证双方约定在编码字符串前加上了此次认证的方式和一个空格: Basic: Authorization: Basic RmlzYWRzYWQ6YXNkYWRz
5.服务器接受该认证凭据并返回页面;如果用户凭据非法或无效,服务器可能再次返回401应答码,客户端可以再次提示用户输入口令。

注意:
① 客户端用户名,口令之间用冒号分隔
② 服务端返回认证域,可能会指定凭据字符串的编码方式:
WWW-Authenticate: Basic realm="User Visible Realm", charset="UTF-8"
此时客户端在准备凭据字符串的时候,要使用指定的charset编码凭据
③ 客户端未认证时,服务端需要给客户端必要的认证域提示,效果如下:

BA认证编程实践
项目中利用StaticFileMiddleware+DirectoryBrowserMiddleware做了一个网页文件服务器, 现对该文件服务器设置BA认证。
ASP.NET Core服务端实现BA认证:
实现基本身份认证Handler, 包含认证方式、认证挑战的提示
asp.netcore 添加认证中间件
注册认证中间件
public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOption>
{
private BasicAuthenticationOption authOptions;
public BasicAuthenticationHandler(
IOptionsMonitor<BasicAuthenticationOption> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
authOptions = options.CurrentValue;
}
/// <summary>
/// BA认证过程
/// </summary>
/// <returns></returns>
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.Fail("Missing Authorization Header");
string username, password;
try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(':');
username = credentials[];
password = credentials[];
var isValidUser= IsAuthorized(username,password);
if(isValidUser== false)
{
return AuthenticateResult.Fail("Invalid username or password");
}
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
var claims = new[] {
new Claim(ClaimTypes.NameIdentifier,username),
new Claim(ClaimTypes.Name,username),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return await Task.FromResult(AuthenticateResult.Success(ticket));
}
/// <summary>
/// 重写该方法以体现身份验证挑战(401)时发生时提示
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{Options.Realm}\",charset=\"utf-8\"";
await base.HandleChallengeAsync(properties);
}
/// <summary> 进行BA认证,此处不关注该方法
/// override the method to influence what happens when an forbidden response (403)
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
{
await base.HandleForbiddenAsync(properties);
}
// BA认证:账户、密码匹配逻辑
private bool IsAuthorized(string username, string password)
{
return username.Equals(authOptions.UserName, StringComparison.InvariantCultureIgnoreCase)
&& password.Equals(authOptions.UserPwd);
}
}
// 添加BA认证计划services.AddAuthentication(BasicAuthentication.DefaultScheme)
.AddScheme<BasicAuthenticationOption, BasicAuthenticationHandler>(BasicAuthentication.DefaultScheme,null);
// 这里我使用UseWhen方式注册认证中间件: 对该网站部分资源 开启基本身份认证app.UseWhen(
predicate:x => x.Request.Path.StartsWithSegments(new PathString(_protectedResourceOption.Path)),
configuration:appBuilder => appBuilder.UseAuthentication()
);
客户端:
- 添加认证请求Handler
- 以上述Handler 配置命名HtttpClient
/// <summary>
/// BA认证请求Handler /// </summary>
public class BasicAuthenticationClientHandler : HttpClientHandler
{
public static string BAHeaderNames = "authorization";
private RemoteBasicAuth _remoteAccount;
public BasicAuthenticationClientHandler(RemoteBasicAuth remoteAccount)
{
_remoteAccount = remoteAccount;
AllowAutoRedirect = false;
UseCookies = true;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var authorization = $"{_remoteAccount.UserName}:{_remoteAccount.Password}";
var authorizationBased64 = "Basic " + Convert.ToBase64String(new ASCIIEncoding().GetBytes(authorization));
request.Headers.Remove(BAHeaderNames);
request.Headers.Add(BAHeaderNames, authorizationBased64);
return base.SendAsync(request, cancellationToken);
}
}
// 配置命名HttpClientservices.AddHttpClient("eqid-ba-request", x =>
x.BaseAddress = new Uri(_proxyOption.Scheme +"://"+ _proxyOption.Host+":"+_proxyOption.Port ) )
.ConfigurePrimaryHttpMessageHandler(y => new BasicAuthenticationClientHandler(_remoteAccount){} )
.SetHandlerLifetime(TimeSpan.FromMinutes())
.AddPolicyHandler(GetRetryPolicy());
That's All . BA认证是随处可见的基础认证协议,本文期待以最清晰的方式帮助你理解协议,最优雅的方式提供编程实践思路。
感谢您的认真阅读,如有问题请大胆斧正,如果您觉得本文对你有用,不妨右下角点个
或加关注。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置注明本文的作者及原文链接,否则保留追究法律责任的权利。
ASP.NET Core实现 随处可见的基本身份认证的更多相关文章
- ASP.NET Core[源码分析篇] - Authentication认证
原文:ASP.NET Core[源码分析篇] - Authentication认证 追本溯源,从使用开始 首先看一下我们通常是如何使用微软自带的认证,一般在Startup里面配置我们所需的依赖认证服务 ...
- 【asp.net core 系列】13 Identity 身份验证入门
0. 前言 通过前两篇我们实现了如何在Service层如何访问数据,以及如何运用简单的加密算法对数据加密.这一篇我们将探索如何实现asp.net core的身份验证. 1. 身份验证 asp.net ...
- ASP.NET Core Identity 实战(3)认证过程
如果你没接触过旧版Asp.Net Mvc中的 Authorize 或者 Cookie登陆,那么你一定会疑惑 认证这个名词,这太正式了,这到底代表这什么? 获取资源之前得先过两道关卡Authentica ...
- ASP.NET Core WebAPI中使用JWT Bearer认证和授权
目录 为什么是 JWT Bearer 什么是 JWT JWT 的优缺点 在 WebAPI 中使用 JWT 认证 刷新 Token 使用授权 简单授权 基于固定角色的授权 基于策略的授权 自定义策略授权 ...
- asp.net core 同时添加Identity和Bearer认证
是这样的,网上介绍的Oauth认证一般都是授权服务器和资源服务器分开,但是我只想在一个网站中使用asp.net core自带的Identity认证给用户访问网站用,同时提供一些api接口通过Token ...
- 【.NET Core微服务实战-统一身份认证】开篇及目录索引
简介 学习.NETCORE也有1年多时间了,发现.NETCORE项目实战系列教程很少,都是介绍开源项目或基础教程,对于那些观望的朋友不能形成很好的学习思路,遇到问题怕无法得到解决而不敢再实际项目中 ...
- ASP.Net Core 3.0 中使用JWT认证
JWT认证简单介绍 关于Jwt的介绍网上很多,此处不在赘述,我们主要看看jwt的结构. JWT主要由三部分组成,如下: HEADER.PAYLOAD.SIGNATURE HEADER包 ...
- asp.net core系列 60 Ocelot 构建服务认证示例
一.概述 在Ocelot中,为了保护下游api资源,用户访问时需要进行认证鉴权,这需要在Ocelot 网关中添加认证服务.添加认证后,ReRoutes路由会进行身份验证,并使用Ocelot的基于声明的 ...
- 重新拾取:ASP.NET Core WebApi 使用Swagger支持授权认证
园子里已经有很多.NET Core 集成Swagger的文章,但对于使用授权的介绍蛮少的. public static class SwaggerServiceExtensions { public ...
随机推荐
- PyQuery详解
1.What is Pyquery? 答:灵活强大的网页解析库 2.安装: pip3 install pyquery 3.基本使用 初始化操作: 前言:在介绍之前小伙伴们我们先来了解下CSS的基本语法 ...
- 【原创】整合Spring4+Hibernate4+Struts2时NullPointerException问题解决
1.开场白 相信SSH初学者肯定遇到过这个问题,但是又是百思不得其解,明白了之后就恍然大悟. 2.问题描述 程序实现过程是UserAction中调用UserService,UserService的实现 ...
- 从一个微型例子看“C/C++的内存分配机制”和“数组变量名与指针变量名”(转)
C++的内存有五大分区:堆区.栈区.自由存储区.全局/静态存储区.常量存储区. 五个数据段:数据段.代码段.BSS段.堆.栈 内存分配方式有三种: 从静态存储区域分配.内存在程序编译的时候就已经分配好 ...
- 微信小程序-统一下单、微信支付(Java后台)
1.首先分享 微信统一下单接口: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1 微信接口 签名 对比网址: https: ...
- 进阶-JMS 知识梳理
JMS 一. 概述与介绍 ActiveMQ 是Apache出品,最流行的.功能强大的即时通讯和集成模式的开源服务器.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Pro ...
- 怎么确定Oracle客户端安装成功
可通过能否登录sqlplus来判断是否安装成功. 操作系统:windows10 oracle版本:oracle 11g 步骤: 1.电脑win键+R键,输入cmd,进入命令提示符. 2.命令行中输入: ...
- SpringMVC中参数绑定
SpringMVC中请求参数的接收主要有两种方式, 一种是基于HttpServletRequest对象获取, 另外一种是通过Controller中的形参获取 一 通过HttpServletReque ...
- 解决redis connection refused: connect无法连接redis
环境 VM VirtualBox安装虚拟机CentOS 7 1.Redis.conf配置文件中 注释掉 bind 127.0.0.1 2.防火墙关闭(或添加可访问的端口,具体不在此描述) 最后一个坑 ...
- 跟我学ASP.NET MVC之七:SportsStrore一个完整的购物车
摘要: SportsStore应用程序进展很顺利,但是我不能销售产品直到设计了一个购物车.在这篇文章里,我就将创建一个购物车. 在目录下的每个产品旁边添加一个添加到购物车按钮.点击这个按钮将显示客户到 ...
- map用法
描述: map()会根据提供的参数对指定序列做映射. 语法: map(function,iterable) function:函数以参数列表中的每一个元素调用function函数,返回包含每次func ...