概览

在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认证:

  1. 实现基本身份认证Handler, 包含认证方式、认证挑战的提示

  2. asp.netcore 添加认证中间件

  3. 注册认证中间件

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()
    );

客户端:

  1. 添加认证请求Handler
  2. 以上述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认证是随处可见的基础认证协议,本文期待以最清晰的方式帮助你理解协议,最优雅的方式提供编程实践思路。

作者:Julian_酱

感谢您的认真阅读,如有问题请大胆斧正,如果您觉得本文对你有用,不妨右下角点个或加关注。

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置注明本文的作者及原文链接,否则保留追究法律责任的权利。

ASP.NET Core实现 随处可见的基本身份认证的更多相关文章

  1. ASP.NET Core[源码分析篇] - Authentication认证

    原文:ASP.NET Core[源码分析篇] - Authentication认证 追本溯源,从使用开始 首先看一下我们通常是如何使用微软自带的认证,一般在Startup里面配置我们所需的依赖认证服务 ...

  2. 【asp.net core 系列】13 Identity 身份验证入门

    0. 前言 通过前两篇我们实现了如何在Service层如何访问数据,以及如何运用简单的加密算法对数据加密.这一篇我们将探索如何实现asp.net core的身份验证. 1. 身份验证 asp.net ...

  3. ASP.NET Core Identity 实战(3)认证过程

    如果你没接触过旧版Asp.Net Mvc中的 Authorize 或者 Cookie登陆,那么你一定会疑惑 认证这个名词,这太正式了,这到底代表这什么? 获取资源之前得先过两道关卡Authentica ...

  4. ASP.NET Core WebAPI中使用JWT Bearer认证和授权

    目录 为什么是 JWT Bearer 什么是 JWT JWT 的优缺点 在 WebAPI 中使用 JWT 认证 刷新 Token 使用授权 简单授权 基于固定角色的授权 基于策略的授权 自定义策略授权 ...

  5. asp.net core 同时添加Identity和Bearer认证

    是这样的,网上介绍的Oauth认证一般都是授权服务器和资源服务器分开,但是我只想在一个网站中使用asp.net core自带的Identity认证给用户访问网站用,同时提供一些api接口通过Token ...

  6. 【.NET Core微服务实战-统一身份认证】开篇及目录索引

    简介 ​ 学习.NETCORE也有1年多时间了,发现.NETCORE项目实战系列教程很少,都是介绍开源项目或基础教程,对于那些观望的朋友不能形成很好的学习思路,遇到问题怕无法得到解决而不敢再实际项目中 ...

  7. ASP.Net Core 3.0 中使用JWT认证

    JWT认证简单介绍     关于Jwt的介绍网上很多,此处不在赘述,我们主要看看jwt的结构.     JWT主要由三部分组成,如下: HEADER.PAYLOAD.SIGNATURE HEADER包 ...

  8. asp.net core系列 60 Ocelot 构建服务认证示例

    一.概述 在Ocelot中,为了保护下游api资源,用户访问时需要进行认证鉴权,这需要在Ocelot 网关中添加认证服务.添加认证后,ReRoutes路由会进行身份验证,并使用Ocelot的基于声明的 ...

  9. 重新拾取:ASP.NET Core WebApi 使用Swagger支持授权认证

    园子里已经有很多.NET Core 集成Swagger的文章,但对于使用授权的介绍蛮少的. public static class SwaggerServiceExtensions { public ...

随机推荐

  1. jQuery匿名函数$(function(){ }

    搬运原地址:https://zhidao.baidu.com/question/473318430.html $(function(){ }实际上是匿名函数.这是JQuery的语法,$表示JQuery ...

  2. 界面渐变特效 -- CSS实现 -- 兼容IE8

    特别注意:里面的RGB颜色值必须要全写,不能使用缩写.左右:background: -webkit-gradient(linear, 0 0, 0 100%, from(#80c1e7), to(#2 ...

  3. 单片机开发——01工欲善其事必先利其器(Keil软件安装破解)

        本文是博主<单片机开发>博客第一篇文章,主要讲述51单片机编程软件Keil uVision4的安装及破解过程. 1. Keil uVision4安装包文件      PATH:链接 ...

  4. 构建具有用户身份认证的 Ionic 应用

    序言:本文主要介绍了使用 Ionic 和 Cordova 开发混合应用时如何添加用户身份认证.教程简易,对于 Ionic 入门学习有一定帮助.因为文章是去年发表,所以教程内关于 Okta 的一些使用步 ...

  5. jsp 条件查询、列表分页

    条件查询 dao //根据搜索条件筛选数据 public List<User> GetUserBySearch(String userName, String sex) throws SQ ...

  6. 进阶-JMS 知识梳理

    JMS 一. 概述与介绍 ActiveMQ 是Apache出品,最流行的.功能强大的即时通讯和集成模式的开源服务器.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Pro ...

  7. 读《图解HTTP》有感-(返回结果的HTTP状态码)

    写在前面 HTTP状态码是由服务端产生,用于告诉客户端,服务端处理结果的编码 正文 1.状态码的作用是什么?具有什么特征? 状态码的作用是当客户端向服务器发送请求时,描述服务器的响应结果(如:服务器正 ...

  8. spring事务机制

    一.Java动态代理 1.定义 Java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 默认情况下会采用JDK的动态代理实现AOP . 2. ...

  9. [译文]Domain Driven Design Reference(三)—— 模型驱动设计的构建模块

    本书是Eric Evans对他自己写的<领域驱动设计-软件核心复杂性应对之道>的一本字典式的参考书,可用于快速查找<领域驱动设计>中的诸多概念及其简明解释. 其它本系列其它文章 ...

  10. CAS 4.0.x 自定义登录页面

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] CAS默认登录页面 复制一个新的页面管理页面 修改页面引用 修改casproperties 修改casLoginViewjs ...