using MessengerApi.Contracts.Models.Scoped; using MessengerApi.Models; using MessengerApi.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 MessengerApi.Handlers { /// /// Validates our permananet API keys sent over as Bearer tokens. /// public class CustomBearerAuthenticationHandler : AuthenticationHandler { private readonly IMemoryCache memoryCache; public CustomBearerAuthenticationHandler( IOptionsMonitor options, ILoggerFactory loggerFactory, UrlEncoder encoder, IMemoryCache memoryCache) : base(options, loggerFactory, encoder) { this.memoryCache = memoryCache; } protected override Task HandleAuthenticateAsync() { const string HEADER = "Authorization"; const string PREFIX = "Bearer "; Context.RequestServices.GetRequiredService(); // creates the object in scope. 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(this.memoryCache.TryGetValue(token, out CachedIdentity oldCache)) { var identity = Context.RequestServices.GetRequiredService(); identity.User = oldCache.User; identity.UserRoutes = oldCache.UserRoutes; return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(oldCache.ClaimsPrincipal, Scheme.Name))); } else { var unitOfWork = Context.RequestServices.GetRequiredService(); var user = unitOfWork.Users.SingleByApiKeyAndEnabled(Guid.Parse(token), true); var routes = unitOfWork.UserRoutes.GetAllByUser(user).ToArray(); var principal = new ClaimsPrincipal( new ClaimsIdentity( new List { new Claim(ClaimTypes.NameIdentifier, user.Name), new Claim(ClaimTypes.Name, user.Name) }, Scheme.Name)); var cache = new CachedIdentity { ClaimsPrincipal = principal, User = user, UserRoutes = routes }; this.memoryCache.Set(token, cache, TimeSpan.FromMinutes(5)); var identity = Context.RequestServices.GetRequiredService(); identity.User = cache.User; identity.UserRoutes = cache.UserRoutes; return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(cache.ClaimsPrincipal, Scheme.Name))); } } } }