using Microsoft.AspNetCore.Authentication; using WebDesktopBackend.Entitys.Tokens; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System.Text.Encodings.Web; using System.Threading.Tasks; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using WebDesktopBackend.Contract.Persistance; using WebDesktopBackend.Entitys.Permissions; using WebDesktopBackend.Security.Authorization; #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously namespace WebDesktopBackend.Security.Authentication { public class JwtTokenAuthenticationHandler : AuthenticationHandler { private readonly ITokenRepository _tokens; private readonly IGroupRepository _groups; public JwtTokenAuthenticationHandler( IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, ITokenRepository tokens, IGroupRepository groups) : base(options, logger, encoder, clock) { _tokens = tokens; _groups = groups; } protected override async Task HandleAuthenticateAsync() { var accessToken = GetAccessToken(); if (accessToken == null) return AuthenticateResult.Fail("Access Token invalid"); var refreshToken = _tokens.GetRefreshToken(accessToken.RefreshTokenId); if (refreshToken == null) return AuthenticateResult.Fail("Refresh Token invalid"); if (!_tokens.ValidateRefreshToken(refreshToken.Id)) return AuthenticateResult.Fail("Refresh Token invalid"); bool valid = _tokens.ValidateAccessToken(accessToken.Id); return valid ? AuthenticateResult.Success(GetAuthenticationTicket(accessToken, refreshToken)) : AuthenticateResult.Fail("Access Token invalid"); } private AuthenticationTicket GetAuthenticationTicket(AccessToken accessToken, RefreshToken refreshToken) { List claims = GenerateClaims(accessToken, refreshToken); ClaimsPrincipal principal = new ClaimsPrincipal(); principal.AddIdentity(new ClaimsIdentity(claims, JwtTokenAuthentication.Scheme)); AuthenticationTicket ticket = new AuthenticationTicket(principal, Scheme.Name); return ticket; } private List GenerateClaims(AccessToken accessToken, RefreshToken refreshToken) { List claims = new List() { new (CustomClaimTypes.AccessTokenId, accessToken.Id), new (CustomClaimTypes.RefreshTokenId, refreshToken.Id), new (CustomClaimTypes.UserId, refreshToken.UserId), }; Permission[] permissions = _groups.GetUserPermissions(refreshToken.UserId) .Where(perm => perm.Type == Permission.Allow).ToArray(); claims.AddRange(permissions.Select(permission => new Claim(CustomClaimTypes.Permission, permission.PermissionName))); return claims; } private AccessToken GetAccessToken() { string key = Request.Headers["Authorization"]; if (string.IsNullOrEmpty(key)) { key = Request.Query["token"]; } AccessToken token = _tokens.GetAccessToken(key); return token; } } } #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously