Archived
Private
Public Access
1
0
This commit is contained in:
2022-12-18 13:30:02 +01:00
commit 0e94ffa3c6
85 changed files with 26673 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
#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");
}

View File

@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
namespace ProjectManager.Backend.Security;
public sealed class AuthorizedAttribute : TypeFilterAttribute {
public AuthorizedAttribute(params string[] permission) : base(typeof(AuthorizationHandler)) {
Arguments = new object[] { permission };
}
}
public sealed class AuthorizationHandler : IAuthorizationFilter {
private readonly string[] _permissions;
public AuthorizationHandler(params string[] permissions) {
_permissions = permissions;
}
public void OnAuthorization(AuthorizationFilterContext context) {
if (context.Filters.Any(item => item is IAllowAnonymousFilter)) return;
if (context.HttpContext.User.Identity?.IsAuthenticated != true) {
context.Result = new UnauthorizedResult();
return;
}
//TODO: Handle Permissions
}
}

View File

@@ -0,0 +1,19 @@
namespace ProjectManager.Backend.Security;
public interface ITokenContext {
public bool IsAuthenticated { get; }
public string TokenId { get; }
public string UserId { get; }
}
public sealed class TokenContext : ITokenContext {
private readonly IHttpContextAccessor _accessor;
public bool IsAuthenticated => _accessor.HttpContext?.User.Identity?.IsAuthenticated == true;
public string TokenId => _accessor.HttpContext?.User.GetTokenId();
public string UserId => _accessor.HttpContext?.User.GetUserId();
public TokenContext(IHttpContextAccessor accessor) {
_accessor = accessor;
}
}