ASP.NETCore编程实现基本认证

简介: 在HTTP中,HTTP基本认证(Basic Authentication)是一种允许浏览器或其他客户端程序使用(用户名,口令)请求资源的身份验证方式,不要求cookie,session identifier、login page等标记或载体。 所有浏览器据支持HTTP基本认证协议基本身证原理不保证传输凭证的安全性,仅被based64编码,并没有encrypted或者hashed,一般部署在互信的内网,在公网上应用BA协议通常与https结合。

HTTP基本认证


   在HTTP中,HTTP基本认证(Basic Authentication)是一种允许浏览器或其他客户端程序使用(用户名,口令)请求资源的身份验证方式,不要求cookie,session identifier、login page等标记或载体。  


  • 所有浏览器据支持HTTP基本认证协议


  • 基本身证原理不保证传输凭证的安全性,仅被based64编码,并没有encrypted或者hashed,一般部署在互信的内网,在公网上应用BA协议通常与https结合。

BA标准协议


BA协议的实施主要依靠约定的请求头/响应头, 典型的浏览器和服务器的BA认证流程:


① 浏览器请求应用了BA的网站,服务端响应一个401认证失败响应码,并写入WWW-Authenticate响应头,指示服务端支持BA协议。


    HTTP/1.1 401 UnauthorizedWWW-Authenticate: Basic realm="our site"


    或在初次请求时发送正确Authorization标头,从而避免被质询


    ② 客户端以based64(用户名:口令) 作为Authorization标头值,重新发送请求:

    Authorization: Basic userid:password


    e15be3c1996203a490ed4e0fb80817c4.png


    认证的范围与realm相关,准确的realm由服务端定义,因为服务端可能有多个不同的realm.


    BA编程实践


        ASP.NET Core网站利用FileServerMiddleware将部分路径映射到文件资源,对该资源访问路径应用Http基本认证。


    服务端实现BA认证


      ①  实现基本认证Handler:认证、无口令质询、质询失败逻辑


      # ......namespace EqidManager.Services{    public static class BasicAuthenticationScheme    {        public const string DefaultScheme = "Basic";    }    public class BasicAuthenticationOption:AuthenticationSchemeOptions    {        public string Realm { get; set; }        public string UserName { get; set; }        public string UserPwd { get; set; }    }
          public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOption>    {        private readonly BasicAuthenticationOption authOptions;        public BasicAuthenticationHandler(            IOptionsMonitor<BasicAuthenticationOption> options,            ILoggerFactory logger,            UrlEncoder encoder,            ISystemClock clock)            : base(options, logger, encoder, clock)        {            authOptions = options.CurrentValue;        }
              /// <summary>        /// 认证逻辑        /// </summary>        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[0];                 password = credentials[1];                 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>        /// 质询        /// </summary>        protected override async Task HandleChallengeAsync(AuthenticationProperties properties)        {            Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{Options.Realm}\"";            await base.HandleChallengeAsync(properties);        }
              /// <summary>        /// 认证失败        /// </summary>        protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)        {           await base.HandleForbiddenAsync(properties);         }        private bool IsAuthorized(string username, string password)        {            return username.Equals(authOptions.UserName, StringComparison.InvariantCultureIgnoreCase)                   && password.Equals(authOptions.UserPwd);        }    }}

         

      ②  实现BasicAuthenticationMiddleware: 要求对HttpContext应用BA Scheme。


        // HTTP基本认证Middleware public static class BasicAuthentication {        public static void UseBasicAuthentication(this IApplicationBuilder app)        {            app.UseMiddleware<BasicAuthenticationMiddleware>();        } }public class BasicAuthenticationMiddleware{     private readonly RequestDelegate _next;     private readonly ILogger _logger;     public BasicAuthenticationMiddleware(RequestDelegate next, ILoggerFactory LoggerFactory)     {        _next = next;        _logger = LoggerFactory.CreateLogger<BasicAuthenticationMiddleware>();     }     public async Task Invoke(HttpContext httpContext, IAuthenticationService authenticationService)     {       var authenticated = await authenticationService.AuthenticateAsync(httpContext, BasicAuthenticationScheme.DefaultScheme);       _logger.LogInformation("Access Status:" + authenticated.Succeeded);       if (!authenticated.Succeeded)       {           await authenticationService.ChallengeAsync(httpContext, BasicAuthenticationScheme.DefaultScheme, new AuthenticationProperties { });           return;       }       await _next(httpContext);     }}


        ③  ASP.NET Core 添加BA Scheme , 为证资源路径用BA中间件,注意这里使用UseWhen插入中间件。


          services.AddAuthentication(BasicAuthenticationScheme.DefaultScheme)                .AddScheme<BasicAuthenticationOption, BasicAuthenticationHandler>(BasicAuthenticationScheme.DefaultScheme,null);app.UseWhen(            predicate:x => x.Request.Path.StartsWithSegments(new PathString(_protectedResourceOption.Path)),            configuration:appBuilder => { appBuilder.UseBasicAuthentication();}    );

          现可在浏览器测试:


          516b7468f9d3cc7a998473b8c2ac6fe0.jpg


          进一步思考?


          以上是浏览器在BA协议中的行为:可尝试程序自动向服务端发起BA请求,需要的同学看博客园源码。


          That's All .  BA认证是常见的基础认证协议,文章期待以清晰的方式传递协议原理和编程实现。

          相关文章
          |
          30天前
          |
          存储 开发框架 安全
          ASP.NET WebApi 如何使用 OAuth2.0 认证
          ASP.NET WebApi 如何使用 OAuth2.0 认证
          |
          4月前
          |
          开发框架 .NET Java
          ASP.NET Core高级编程--C#基本特性(一)
          本文章简略介绍C#的部分特性
          |
          11月前
          |
          开发框架 .NET 数据库
          asp.net企业费用报销管理信息系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
          asp.net 企业费用报销管理信息系统是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使 用c#语言开发 应用技术:asp.net c#+sqlserver 开发工具:vs2010 +sqlserver
          83 0
          |
          开发框架 中间件 .NET
          Asp.Net Core认证-Jwt-基础篇
          Asp.Net Core认证-Jwt-基础篇
          177 0
          |
          开发框架 算法 安全
          在 Asp.Net Core 中什么是认证和授权
          认证(Authentication) 和 授权(Authorization)在 Asp.Net core 充当了两个不同的职责。有的老伙计在理解的时候还存在误解。本文我们将会通过一些简单的例子来说明这两个概念。
          157 0
          在 Asp.Net Core 中什么是认证和授权
          |
          存储 开发框架 .NET
          ASP.NET Core 中jwt授权认证的流程原理
          ASP.NET Core 中jwt授权认证的流程原理
          302 0
          ASP.NET Core 中jwt授权认证的流程原理
          |
          存储 开发框架 安全
          ASP.NET Core 3.0一个jwt的轻量角色/用户、单个API控制的授权认证库
          ASP.NET Core 3.0一个jwt的轻量角色/用户、单个API控制的授权认证库
          183 0
          ASP.NET Core 3.0一个jwt的轻量角色/用户、单个API控制的授权认证库
          |
          开发框架 前端开发 .NET
          使用Asp.Net Identity 2.0 认证邮箱激活账号(附DEMO)
          一个星期前,也就是3月20日,微软发布了Asp.Net Identity 2.0 RTM。功能更加强大,也更加稳定。Identity这个东西现在版本还比较低,每次发布新版本都会有较多改动。

          相关实验场景

          更多