ASP.NET Core 实现基本认证

摘要:
Authorization:Basicuserid:password所以在HTTP基本认证中认证范围与realm有关˃一般浏览器客户端对于www-Authenticate质询结果,会弹出口令输入窗.BA编程实践aspnetcore网站利用FileServerMiddleware将路径映射到某文件资源,现对该文件资源访问路径应用HttpBA协议。

HTTP基本认证

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

- 所有浏览器据支持HTTP基本认证方式

- 基本身证原理不保证传输凭证的安全性,仅被based64编码,并没有encrypted或者hashed,一般部署在客户端和服务端互信的网络,在公网中应用BA认证通常与https结合

https://en.wikipedia.org/wiki/Basic_access_authentication

BA标准协议

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

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

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="our site" # WWW-Authenticate响应头包含一个realm域属性,指明HTTP基本认证的是这个资源集

或客户端在第一次请求时发送正确Authorization标头,从而避免被质询

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

Authorization: Basic userid:password

ASP.NET Core 实现基本认证第1张

所以在HTTP基本认证中认证范围与 realm有关(具体由服务端定义)

> 一般浏览器客户端对于www-Authenticate质询结果,会弹出口令输入窗.

BA编程实践

aspnetcore网站利用FileServerMiddleware 将路径映射到某文件资源, 现对该 文件资源访问路径应用 Http BA协议。

ASP.NET Core服务端实现BA认证:

① 实现服务端基本认证的认证过程、质询逻辑

实现基本身份认证交互中间件BasicAuthenticationMiddleware ,要求对HttpContext使用 BA.Scheme

③ASP.NET Core 添加认证计划 , 为文件资源访问路径启用 BA中间件,注意使用UseWhen插入中间件

usingSystem;
usingSystem.Net.Http.Headers;
usingSystem.Security.Claims;
usingSystem.Text;
usingSystem.Text.Encodings.Web;
usingSystem.Threading.Tasks;
usingMicrosoft.AspNetCore.Authentication;
usingMicrosoft.Extensions.Logging;
usingMicrosoft.Extensions.Options;
namespaceEqidManager.Services
{
    public static classBasicAuthenticationScheme
    {
        public const string DefaultScheme = "Basic";
    }
    public classBasicAuthenticationOption:AuthenticationSchemeOptions
    {
        public string Realm { get; set; }
        public string UserName { get; set; }
        public string UserPwd { get; set; }
    }
    public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOption>
    {
        private readonlyBasicAuthenticationOption authOptions;
        publicBasicAuthenticationHandler(
            IOptionsMonitor<BasicAuthenticationOption>options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock)
            : base(options, logger, encoder, clock)
        {
            authOptions =options.CurrentValue;
        }
        /// <summary>
        ///认证
        /// </summary>
        /// <returns></returns>
        protected override async Task<AuthenticateResult>HandleAuthenticateAsync()
        {
            if (!Request.Headers.ContainsKey("Authorization"))
                return AuthenticateResult.Fail("Missing Authorization Header");
            stringusername, 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[] {
                newClaim(ClaimTypes.NameIdentifier,username),
                newClaim(ClaimTypes.Name,username),
            };
            var identity = newClaimsIdentity(claims, Scheme.Name);
            var principal = newClaimsPrincipal(identity);
            var ticket = newAuthenticationTicket(principal, Scheme.Name);
            return awaitTask.FromResult(AuthenticateResult.Success(ticket));
        }
        /// <summary>
        ///质询
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        protected override asyncTask HandleChallengeAsync(AuthenticationProperties properties)
        {
            Response.Headers["WWW-Authenticate"] = $"Basic realm="{Options.Realm}"";
            await base.HandleChallengeAsync(properties);
        }
        /// <summary>
        ///认证失败
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        protected override asyncTask HandleForbiddenAsync(AuthenticationProperties properties)
        {
           await base.HandleForbiddenAsync(properties); 
        }
        private bool IsAuthorized(string username, stringpassword)
        {
            returnusername.Equals(authOptions.UserName, StringComparison.InvariantCultureIgnoreCase)
                   &&password.Equals(authOptions.UserPwd);
        }
    }
}
// HTTP基本认证Middleware
public static classBasicAuthentication { public static void UseBasicAuthentication(thisIApplicationBuilder app) { app.UseMiddleware<BasicAuthenticationMiddleware>(); } } public classBasicAuthenticationMiddleware { private readonlyRequestDelegate _next; private readonlyILogger _logger; publicBasicAuthenticationMiddleware(RequestDelegate next, ILoggerFactory LoggerFactory) { _next =next;
_logger
= LoggerFactory.CreateLogger<BasicAuthenticationMiddleware>(); } public asyncTask Invoke(HttpContext httpContext, IAuthenticationService authenticationService) { var authenticated = awaitauthenticationService.AuthenticateAsync(httpContext, BasicAuthenticationScheme.DefaultScheme); _logger.LogInformation("Access Status:" +authenticated.Succeeded); if (!authenticated.Succeeded) { await authenticationService.ChallengeAsync(httpContext, BasicAuthenticationScheme.DefaultScheme, newAuthenticationProperties { }); return; } await_next(httpContext); } }

Startup.cs 文件添加并启用HTTP基本认证

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

以上BA认证的服务端已经完成,现在可以在浏览器测试:

ASP.NET Core 实现基本认证第2张

ASP.NET Core 实现基本认证第3张进一步思考?

浏览器在BA协议中行为: 编程实现BA客户端,要的同学可以直接拿去

ASP.NET Core 实现基本认证第4张ASP.NET Core 实现基本认证第5张
    /// <summary>
    ///BA认证请求Handler
    /// </summary>
    public classBasicAuthenticationClientHandler : HttpClientHandler
    {
        public static string BAHeaderNames = "authorization";
        privateRemoteBasicAuth _remoteAccount;
        publicBasicAuthenticationClientHandler(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(newASCIIEncoding().GetBytes(authorization));
            request.Headers.Remove(BAHeaderNames);
            request.Headers.Add(BAHeaderNames, authorizationBased64);
            return base.SendAsync(request, cancellationToken);
        }
    }
  //生成basic Authentication请求
            services.AddHttpClient("eqid-ba-request", x =>
                   x.BaseAddress = new Uri(_proxyOption.Scheme +"://"+ _proxyOption.Host+":"+_proxyOption.Port ) )
               .ConfigurePrimaryHttpMessageHandler(y => newBasicAuthenticationClientHandler(_remoteAccount){} )
               .SetHandlerLifetime(TimeSpan.FromMinutes(2));
仿BA认证协议中的浏览器行为

That's All . BA认证是随处可见的基础认证协议,本文期待以最清晰的方式帮助你理解协议:

实现了基本认证协议服务端,客户端;

作者:JulianHuang
感谢您的认真阅读,如有问题请大胆斧正;觉得有用,请下方ASP.NET Core 实现基本认证第6张或加关注。本文欢迎转载,但请保留此段声明,且在文章页面明显位置注明本文的作者及原文链接。

免责声明:文章转载自《ASP.NET Core 实现基本认证》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇快速生成apk 自动发布到网站 便于测试mysql 5.7 迁移数据方案下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

全网最详细的最新稳定OSSEC搭建部署(ossec-server(CentOS7.X)和ossec-agent(CentOS7.X))(图文详解)

OSSEC是一款开源的基于主机的入侵检测系统,可以简称为HIDS。它具备日志分析,文件完整性检查,策略监控,rootkit检测,实时报警以及联动响应等功能。详细的介绍和文档可以参考官网网站:http://www.ossec.net/环境本文中的环境极其简单,两台CentOS7虚拟机。CentOS7的安装详解服务端:  计算机名:ossec-server  I...

nginx 浏览php的时候会变成下载

php的时候会变成下载:这是因为nginx没有设置好碰到php文件时,要传递到后方的php解释器。当然啦,你的php-fpm解析器也需要正常运行,并监听好9000端口,才能最终生效并有效处理php脚本。windows下开启监听的办法,php-cgi.exe-b127.0.0.1:9000-cphpphp.ini待续:。。。。。...

fiddler抓包+雷电模拟器 完成手机app抓包的配置

找到系统应用,点击设置,点击无线网络WLAN—˃左键常按点击已连接网络—˃修改网络鼠标左键长按在桌面找到下面这个文件之后双击打开上面证书弄完之后。可以说本机已经安装过证书了,如果你能在模拟器上找到这个证书就不用将这个证书再拉入模拟器了在模拟器中打开系统应用—˃设置—˃安全—˃从SD卡安装。找到FiddlerRoot.cer文件,按提示导入即可,注意在此过程需...

centos登录密码正确但一直报login incorrect错误(错误赋予权限)

3、 若要修改文件权限,请在无法登录之前仔细调用操作。回想一下,您以前在Linux中遇到过由文件权限引起的问题。尝试检查系统日志/var/log/secure。...

IPv6地址的ping、telnet等操作

最近,我在研究https协议如何传输数据。我用wireshark捕捉数据包并分析它们。我发现客户端和谷歌网站在传输数据时使用了IPv6地址,因此我测试了与IPv6地址相关的基本功能。...

CMD命令行正确显示中文

如果要在命令行中正确显示UTF-8字符,可以执行以下步骤:1.打开CMD exe命令行窗口2.通过chcp命令更改代码页。UTF-8的代码页为65001chcp65001。执行此操作后,代码页将变为UTF-8。但是,UTF-8字符无法在窗口中正确显示。此时,使用type命令显示UTF-8文本文件的内容:typefilename Txt4。上述操作无法完全解决...