82 lines
3.6 KiB
C#
82 lines
3.6 KiB
C#
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<JwtTokenAuthenticationHandlerOptions>
|
|
{
|
|
private readonly ITokenRepository _tokens;
|
|
private readonly IGroupRepository _groups;
|
|
|
|
public JwtTokenAuthenticationHandler(
|
|
IOptionsMonitor<JwtTokenAuthenticationHandlerOptions> options,
|
|
ILoggerFactory logger,
|
|
UrlEncoder encoder,
|
|
ISystemClock clock,
|
|
ITokenRepository tokens,
|
|
IGroupRepository groups)
|
|
: base(options, logger, encoder, clock)
|
|
{
|
|
_tokens = tokens;
|
|
_groups = groups;
|
|
}
|
|
|
|
protected override async Task<AuthenticateResult> 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<Claim> 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<Claim> GenerateClaims(AccessToken accessToken, RefreshToken refreshToken) {
|
|
List<Claim> claims = new List<Claim>() {
|
|
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 |