概览

在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. Android 加载GIF图最佳实践

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/75578109 本文出自[赵彦军的博客] 起因 最近在项目中遇到需要在界面上显示一个 ...

  2. linux环境安装svn并进行多个源码库区分管理

    关于svn的文档有很多大部分已Windows为例子,因公司没有Windows服务器经过一天的曲折终于初步安装了解了svn.下面一些经验希望能帮助新手 本文采用的yum安装(简单快速没必要源码) 1.y ...

  3. C入门语言基础一[可移植性、涉及的三种文件、编程7个步骤、编译器、链接器]

    Review Questions What dose portability mean in the context of programming? 文中讲到的可移植性是什么意思?   C本身是不涉及 ...

  4. android sqlite android.database.CursorIndexOutOfBoundsException: Index 5 requested, with a size of 5

    Cursor c = db.query("user",null,null,null,null,null,null);//查询并获得游标 if(c.moveToFirst()){// ...

  5. python 环境搭建及pycharm的使用

    一.windows 1.上官网下载python3.5  https://www.python.org/downloads/ 2.安装的时候勾选path 3.安装完成后打开cmd 输入python查看安 ...

  6. django优化和扩展(一)

    mysql优化基础 进行django产品开发或上线之前,有必要了解一下mysql的基础知识,orm太过抽象,导致很多朋友对于mysql了解得太少,而且orm不像sqlalchemy那样可以跟mysql ...

  7. zfs文件系统简单使用

    关于ubuntu下zfs的使用参考:https://github.com/zfsonlinux/zfs/wiki/Ubuntu%2016.04%20Root%20on%20ZFS 安装zfs: 启动z ...

  8. Python_字符串连接

    #join() 与split()相反,join()方法用来将列表中多个字符串进行连接,并在相邻两个字符串之间插入指定字符 li=['apple','peach','banana','pear'] se ...

  9. JAVA学习资源分享

    JAVA学习资源分享 最高端的JAVA架构师资源(来自龙果学院 价值¥1399元).JAVA互联网分布式架构(龙果学院 价值¥899元).Spring Boot(2017年最新 包括源码原理分析) + ...

  10. zabbix监控mysql性能

    使用zabbix监控mysql的三种方式 1.只是安装agent 2.启用模板监控 3.启用自定义脚本的模板监控 zabbix中默认有mysql的监控模板.默认已经在zabbix2.2及以上的版本中. ...