using MessengerBroker.Configuration.Model; using MessengerBroker.Models; using MessengerBroker.Models.Scoped; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using System.Security.Claims; using System.Text.Encodings.Web; namespace MessengerBroker.Handlers { /// /// Validates our permananet API keys sent over as Bearer tokens. /// public class CustomBearerAuthenticationHandler : AuthenticationHandler { private readonly IMemoryCache memoryCache; private readonly BrokerConfiguration configuration; public CustomBearerAuthenticationHandler( IOptionsMonitor options, ILoggerFactory loggerFactory, UrlEncoder encoder, IMemoryCache memoryCache, BrokerConfiguration configuration) : base(options, loggerFactory, encoder) { this.memoryCache = memoryCache; this.configuration = configuration; } protected override Task HandleAuthenticateAsync() { const string HEADER = "Authorization"; const string PREFIX = "Bearer "; if (!Request.Headers.TryGetValue(HEADER, out var authHeader) || !authHeader.ToString().StartsWith(PREFIX)) { return Task.FromResult(AuthenticateResult.NoResult()); } var token = authHeader.ToString().Substring(PREFIX.Length).Trim(); if(memoryCache.TryGetValue(token, out CachedIdentity oldCache)) { var identity = Context.RequestServices.GetRequiredService(); identity.Server = oldCache.Server; return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(oldCache.ClaimsPrincipal, Scheme.Name))); } else { var brokerId = Guid.Parse(token); var server = configuration.SlaveServers.SingleOrDefault(x => x.BrokerId == brokerId); var principal = new ClaimsPrincipal( new ClaimsIdentity( new List { new Claim(ClaimTypes.NameIdentifier, token), new Claim(ClaimTypes.Name, token) }, Scheme.Name)); var cache = new CachedIdentity { ClaimsPrincipal = principal, Server = server }; memoryCache.Set(token, cache, TimeSpan.FromMinutes(5)); var identity = Context.RequestServices.GetRequiredService(); identity.Server = server; return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(cache.ClaimsPrincipal, Scheme.Name))); } } } }