Archived
Private
Public Access
1
0
This repository has been archived on 2026-02-04. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ProjectManager/ProjectManager.Backend/Security/AuthenticationHandler.cs
2022-12-18 13:30:02 +01:00

86 lines
3.3 KiB
C#

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using ProjectManager.Backend.Apis;
namespace ProjectManager.Backend.Security;
public static class AuthenticationExtensions {
public static AuthenticationBuilder AddCustomAuthentication(this IServiceCollection services, bool configureSwagger = false) {
var builder = services
.AddAuthentication("CustomScheme")
.AddScheme<AuthenticationSchemeOptions, AuthenticationHandler>("CustomScheme", _ => { });
if (configureSwagger) {
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c => {
c.AddSecurityDefinition("CustomScheme", new OpenApiSecurityScheme {
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "CustomScheme"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {{
new OpenApiSecurityScheme {
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "CustomScheme"
},
Scheme = "oauth2",
Name = "CustomScheme",
In = ParameterLocation.Header,
},
ArraySegment<string>.Empty
}});
});
}
return builder;
}
}
public sealed class AuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> {
private readonly ITokenApi _tokens;
public AuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
ITokenApi tokens)
: base(options, logger, encoder, clock) {
_tokens = tokens;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() {
string tokenId = Request.Headers["Authorization"];
if (string.IsNullOrEmpty(tokenId)) tokenId = Request.Query["token"];
string clientIp = Context.Connection.RemoteIpAddress?.ToString();
return !_tokens.ValidateToken(tokenId, clientIp) ? AuthenticateResult.Fail("Token invalid") : AuthenticateResult.Success(GenerateTicket(tokenId));
}
private AuthenticationTicket GenerateTicket(string tokenId) {
var user = _tokens.GetUserFromToken(tokenId);
var claims = new List<Claim> {
new("TokenId", tokenId),
new("UserId", user.UserId)
};
var principal = new ClaimsPrincipal();
principal.AddIdentity(new ClaimsIdentity(claims, Scheme.Name));
return new AuthenticationTicket(principal, Scheme.Name);
}
}
public static class ClaimsPrincipalExtensions {
public static string GetTokenId(this ClaimsPrincipal principal) => principal.FindFirstValue("TokenId");
public static string GetUserId(this ClaimsPrincipal principal) => principal.FindFirstValue("UserId");
}