Http BasicAuth 即 Http 基本認證,其最簡單的實質是,服務器容許客戶端攜帶帳號密碼/加密認證請求頭來訪問受保護資源,例如:算法
curl http://username:password@localhost/api/users
實現訪問受保護資源base64str
實現訪問受保護資源base64str 實際爲 username:password 字符串通過base64算法編碼後的字符串
基本的交互流程以下圖所示api
根據如下步驟,建立一個基本的NetCore項目(基於NetCore3.1版本)瀏覽器
根據上面三個圖所示,咱們便可建立好一個最基本的NetCore項目服務器
經過自定義AuthenticationHandler
實現BasicAuth認證,實現代碼以下:app
using ApiBasicAuth.Models; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http.Headers; using System.Security.Claims; using System.Text; using System.Text.Encodings.Web; using System.Threading.Tasks; namespace ApiBasicAuth.Security { public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> { public BasicAuthenticationHandler( IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { } protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Headers.ContainsKey("Authorization")) { Response.Headers.Add("WWW-Authenticate", @"Basic realm='Secure Area'"); return AuthenticateResult.Fail("Missing Authorization Header"); } User user = null; try { var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); var credentialBytes = Convert.FromBase64String(authHeader.Parameter); var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2); var username = credentials[0]; var password = credentials[1]; if (username.Equals("admin") && password.Equals("password")) { user = new User { Id=1, Username = "admin", Birthday = DateTime.Now }; } } catch { // Base64字符串解碼失敗 return AuthenticateResult.Fail("Invalid Authorization Header"); } if (user == null) return AuthenticateResult.Fail("Invalid Username or Password"); var claims = new[] { new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), new Claim(ClaimTypes.Name, user.Username), }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return AuthenticateResult.Success(ticket); } } }
其中有幾點值得比較注意:curl
Response.Headers.Add("WWW-Authenticate", @"Basic realm='Secure Area'");
在認證失敗時,返回這個請求頭,則是告訴瀏覽器,要求彈出認證信息輸入窗口(瀏覽器自身功能),若沒返回此請求頭,則瀏覽器不會彈出自帶帳號/密碼輸入窗口,直接顯示401if (username.Equals("admin") && password.Equals("password"))
在示例代碼中,直接固定只支持admin帳號,在實際中,因該是根據諸如UserService
等服務層,來判斷用戶帳號信息var claims = new[] { new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), new Claim(ClaimTypes.Name, user.Username), };
在示例中,默認只是給當前用戶設置了兩個基本屬性,在實際中,咱們能夠根據用戶的角色/權限等信息,注入對應的Claim,如:async
var roles = new List<string>(); foreach (var item in roles) { claims.Append(new Claim(ClaimTypes.Role, item)); };
在public void ConfigureServices(IServiceCollection services)
中,增長以下配置ide
services.AddAuthentication("BasicAuthentication") .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);
在public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
中,增長以下配置:ui
app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
至此,項目的認證服務配置,搭建完成編碼
經過上面的章節,咱們已經配置好認證服務,下面則是開始構建Controller,來校驗認證是否生效。以下圖,咱們便攜一個最基本的Controller
namespace ApiBasicAuth.Controllers { [Route("api/[controller]/[action]")] [ApiController] public class UserController : ControllerBase { [HttpGet] [AllowAnonymous] public IActionResult NoSecurity() { return Ok("NoSecurity"); } [HttpGet] [Authorize] public IActionResult Security() { return Ok("Security"); } } }
其中
/api/User/Security
須要認證後才能訪問/api/User/NoSecuirty
不須要認證就能訪問
- [AllowAnonymous] 表示接口任何人都能訪問
- [Authorize] 標識接口須要登錄認證後,才能進行訪問
咱們開始進行校驗:
/api/User/Security
不攜帶認證信息
請求返回401,代表未認證,則表明咱們配置的認證服務已生效。
/api/User/Security
攜帶認證信息
能夠看到,返回Security,代表已經認證經過
/api/User/NoSecurity
不攜帶認證信息
能夠看到,對於無需認證的接口,不攜帶認證信息也能獲取內容。
至此,BasicAuth 認證服務就配置驗證完成,其實咱們能夠經過這個例子,能夠衍生推導出如何實現JWT認證服務,基本原理一致,只是須要稍微修改BasicAuthenticationHandler
配置便可,後續這邊也會編寫NetCore實現自定義JWT認證服務相關文章。
歡迎關注公衆號,獲取最新文章信息