隨處可見的基本身份認證 & 程式設計實現(C#)
基本身份認證Basic Authentication,簡稱BA認證
概覽
HTTP基本身份驗證是一種最簡單的web資源訪問控制的技術,客戶端攜帶username、password去請求伺服器資源,不要求cookie,session identifier、login page等標記或載體。
基本身份認證過程主要在header特定欄位中體現,不需要handshakes。
https://en.wikipedia.org/wiki/Basic_access_authentication
特徵
基本身份認證協議不保證傳輸憑證的安全性,他們僅僅只是被based64編碼,並沒有encrypted或者hashed,因此Basic Authentication為了保密性通常與https結合一起使用。
因為基本身份認證欄位必須在HTTP Header 中傳送,所以web browser需要在一個合理的時間內快取憑據,快取策略因瀏覽器不同而異,IE預設快取15 分鐘。 HTTP不會為客戶端提供一個logout方法,但是有很多方法在瀏覽器中可以清除快取憑據。
<script>document.execCommand('ClearAuthenticationCache');</script>
BA認證的標準協議
客戶端
客戶端使用Authorization Request header 傳送認證憑據,憑據生成方式如下:
-
username、password欄位以冒號分隔(username不能包含冒號)
-
string ---> 位元組
-
Baseed64編碼
-
在編碼後字串前加上Authorization 方法和一個空格
Authorization: Basic RmlzYWRzYWQ6YXNkYWRz
服務端
當服務端設定了基本身份認證服務時,服務端要給未通過認證請求適當的認證提示:
response status code:401 (Unauthorized)
repsonse header:WWW-Authenticate
HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="180.76.176.244"
客戶端表現如下圖:
BA認證的日常應用、實現
日常應用
IIS自帶基本身份驗證,以下是在IIS website中配置使用基本身份認證:
以.N
etCore實踐BA認證
服務端:
-
實現基本身份認證Handler, 包含認證方式、認證挑戰的提示
-
.netcore 新增認證中介軟體
-
註冊認證中介軟體
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[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> /// 重寫該方法以體現身份驗證挑戰(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); } 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啟用一箇中間件: 對某些路徑開啟BA認證 app.UseWhen( predicate:x => x.Request.Path.StartsWithSegments(new PathString(_protectedResourceOption.Path)), configuration:appBuilder => appBuilder.UseAuthentication() );
客戶端:
- 新增認證請求Handler
- 以上述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); } }
// 配置命名HttpClient services.AddHttpClient("eqid-ba-request", x => x.BaseAddress = new Uri(_proxyOption.Scheme +"://"+ _proxyOption.Host+":"+_proxyOption.Port ) ) .ConfigurePrimaryHttpMessageHandler(y => new BasicAuthenticationClientHandler(_remoteAccount){} ) .SetHandlerLifetime(TimeSpan.FromMinutes(2)) .AddPolicyHandler(GetRetryPolicy());
以上應該是從 協議、場景、實現 講述了BA認證的全部知識點 。
--------------如果你覺得文章對你有價值,請點贊或者關注;如有問題請大膽斧正,蟹蟹-------------- ~~。。~~ --------------