Skip to content

Instantly share code, notes, and snippets.

@dj-nitehawk
Last active September 21, 2023 20:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dj-nitehawk/ef60db792a56afc23537238e79257d13 to your computer and use it in GitHub Desktop.
Save dj-nitehawk/ef60db792a56afc23537238e79257d13 to your computer and use it in GitHub Desktop.
Session Auth With FastEndpoints + Swagger
public sealed class Endpoint : EndpointWithoutRequest
{
public override void Configure()
{
Get("/protected");
Claims("userId");
Roles("Some_Role_Name");
Permissions("Some_Permission");
}
public override async Task HandleAsync(CancellationToken c)
{
await SendAsync(new
{
SessionId = HttpContext.Request.Headers[SessionAuth.SessionIdHdrName].FirstOrDefault(),
UserId = User.ClaimValue("userId"),
HasSomeRole = User.IsInRole("Some_Role_Name"),
HasSomePermission = User.HasPermission("Some_Permission")
});
}
}
using FastEndpoints;
using FastEndpoints.Security;
using FastEndpoints.Swagger;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using NSwag;
using System.Security.Claims;
using System.Security.Principal;
using System.Text.Encodings.Web;
var bld = WebApplication.CreateBuilder();
bld.Services
.AddFastEndpoints()
.AddAuthorization()
.AddAuthentication(SessionAuth.SchemeName)
.AddScheme<AuthenticationSchemeOptions, SessionAuth>(SessionAuth.SchemeName, null);
bld.Services
.SwaggerDocument(o =>
{
o.EnableJWTBearerAuth = false;
o.DocumentSettings = s =>
{
s.AddAuth(SessionAuth.SchemeName, new()
{
Name = SessionAuth.SessionIdHdrName,
In = OpenApiSecurityApiKeyLocation.Header,
Type = OpenApiSecuritySchemeType.ApiKey, //this is the only usable option :-(
});
};
});
var app = bld.Build();
app.UseAuthorization()
.UseFastEndpoints()
.UseSwaggerGen();
app.Run();
public sealed class SessionAuth : AuthenticationHandler<AuthenticationSchemeOptions>
{
internal const string SchemeName = "Session";
internal const string SessionIdHdrName = "x-session-id";
public SessionAuth(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) : base(options, logger, encoder, clock) { }
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (IsPublicEndpoint())
return Task.FromResult(AuthenticateResult.NoResult());
var hdrIsPresent = Request.Headers.TryGetValue(SessionIdHdrName, out var sessionId);
if (!hdrIsPresent && !IsValidSession(sessionId))
return Task.FromResult(AuthenticateResult.Fail("Invalid Session!"));
//retrieve the user's claims/roles/permissions from a db/cache and create an auth ticket
var identity = new ClaimsIdentity(
claims: new[]
{
new Claim("userId", "001"),
new Claim("permissions","Some_Permission"),
new Claim("permissions","Another_Permission")
},
authenticationType: Scheme.Name);
var roles = new[]
{
"Some_Role_Name",
"Another_Role_Name"
};
var principal = new GenericPrincipal(identity, roles);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return Task.FromResult(AuthenticateResult.Success(ticket));
}
private bool IsPublicEndpoint() => Context
.GetEndpoint()?
.Metadata.OfType<AllowAnonymousAttribute>()
.Any() is null or true;
private static bool IsValidSession(StringValues sessionId)
{
//validate the session however you wish
return sessionId == "xyz";
}
}
@samld
Copy link

samld commented Sep 20, 2023

Hi! I'm getting a 403 - Forbidden response even though my auth code produces a successful AuthenticateResult with a ticket. What else is there that could be causing this issue?

EDIT: It seems to be caused by the authenticationType that points to the wrong scheme.

@dj-nitehawk
Copy link
Author

@samld so all good?

@samld
Copy link

samld commented Sep 21, 2023

@dj-nitehawk Yeah but I think lines 30 and 37 have to changed to SchemeName instead of Scheme.Name. That's how I fixed it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment