HTTP基本认证
在HTTP中,HTTP基本认证(Basic Authentication)是一种允许浏览器或其他客户端程序使用(用户名,口令)请求资源的身份验证方式,不要求cookie,session identifier、login page等标记或载体。
- 所有浏览器据支持HTTP基本认证协议
- 基本身证原理不保证传输凭证的安全性,仅被based64编码,并没有encrypted或者hashed,一般部署在互信的内网,在公网上应用BA协议通常与https结合。
BA标准协议
BA协议的实施主要依靠约定的请求头/响应头, 典型的浏览器和服务器的BA认证流程:
① 浏览器请求应用了BA的网站,服务端响应一个401认证失败响应码,并写入WWW-Authenticate响应头,指示服务端支持BA协议。
代码语言:javascript复制HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="our site"
或在初次请求时发送正确Authorization标头,从而避免被质询
② 客户端以based64(用户名:口令) 作为Authorization标头值,重新发送请求:
Authorization: Basic userid:password
认证的范围与realm相关,准确的realm由服务端定义,因为服务端可能有多个不同的realm.
> 浏览器客户端,对于WWW-Authenticate响应头弹出了口令输入窗。
BA编程实践
ASP.NET Core网站利用FileServerMiddleware将部分路径映射到文件资源,对该资源访问路径应用Http基本认证。
服务端实现BA认证
① 实现基本认证Handler:认证、无口令质询、质询失败逻辑
代码语言:javascript复制# ......
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。
代码语言:javascript复制// 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插入中间件。
代码语言:javascript复制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();}
);
现可在浏览器测试:
进一步思考?
以上是浏览器在BA协议中的行为:可尝试程序自动向服务端发起BA请求,需要的同学看博客园源码。
That's All . BA认证是常见的基础认证协议,文章期待以清晰的方式传递协议原理和编程实现,要的同学阅读原文。