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认证服务相关文章。
欢迎关注公众号,获取最新文章信息