Our custom session object inherits from AuthUserSession
and the IsAuthenticated
property returns true. We successfully authenticate. API explorer shows us the roles we have set.
Our auth provider basically reads Claims
from the .net ClaimsPrincipal
to populate the custom session object. We have a few custom claims we map to custom properties. A company specific library reads auth/session info from a custom JWT and/or cookie that is exchanged to get session info. Either method results in Claims
being set on the .net ClaimsPrincipal
. I don’t intend to share that code.
In our testing we individually attempted to add ValidateIsAuthenticated
per the documentation, Authenticate
attribute directly on the request dto, implement custom AutoQuery service class decorated with the Authenticate
attribute, and setting a specific role the session had on the request DTO to resolve the issue. All resulted in the related functionality disappearing from the Locode page.
For example: if we make creating a group (see code below) require authentication, create group button disappears. The table still shows up in the navigation menu and we see results.
Everything works as expected as soon as I set a role called Admin
on the custom session object:
GlobalRequestFilters.Add((request, _, __) =>
{
var session = request.SessionAs<CustomAuthUserSession>();
if (session is { IsAuthenticated: true })
{
session.Roles.Add("Admin");
}
});
Reference Code:
public interface IAudit
{
DateTime CreatedDate { get; set; }
string CreatedBy { get; set; }
string CreatedInfo { get; set; }
DateTime ModifiedDate { get; set; }
string ModifiedBy { get; set; }
string ModifiedInfo { get; set; }
}
public abstract class AuditBase : IAudit
{
public DateTime CreatedDate { get; set; }
[Required]
public string CreatedBy { get; set; }
[Required]
public string CreatedInfo { get; set; }
public DateTime ModifiedDate { get; set; }
public string ModifiedBy { get; set; }
public string ModifiedInfo { get; set; }
public ulong RowVersion { get; set; }
}
[Route("/group", "POST", Summary = "Creates a new group")]
// Authenticate attribute causes Locode to stop working
[Authenticate]
public class CreateGroup : AuditableRequest, ICreateDb<Group>, IReturn<GroupCreated>
{
[ValidateNotEmpty(Message="Did This Work?")]
public string Name { get; set; }
}
public class GroupCreated
{
public Guid Id { get; set; }
public ulong RowVersion { get; set; }
}
public class Group : AuditBase
{
[AutoId]
public Guid Id { get; set; }
[Required]
[Unique]
[StringLength(50)]
public string Name { get; set; }
[Reference]
public List<FeatureFlag> FeatureFlags { get; set; }
public ulong RowVersion { get; set; }
}
[UniqueConstraint(nameof(GroupId), nameof(Name))]
public class FeatureFlag : AuditBase
{
[AutoId]
public Guid Id { get; set; }
[ForeignKey(typeof(Group))]
public Guid GroupId { get; set; }
[Required]
[StringLength(75)]
public string Name { get; set; }
public bool IsEnabled { get; set; }
public ulong RowVersion { get; set; }
}
[Route("/group", "GET", Summary = "Retrieves groups")]
//This breaks Locode
//[ValidateIsAuthenticated]
public class GetGroups : QueryDb<Group>
{
}
[Route("/group/{Id}", "DELETE", Summary = "Deletes the specified group")]
//[ValidateIsAuthenticated]
public class DeleteGroup : IDeleteDb<Group>, IReturnVoid
{
public Guid Id { get; set; }
}
[Route("/group/{Id}", "PATCH", Summary = "Patch an existing group for feature flag management")]
// [ValidateIsAuthenticated]
public class PatchGroup : AuditableRequest, IPatchDb<Group>, IReturn<GroupPatched>
{
public Guid Id { get; set; }
public string Name { get; set; }
public ulong RowVersion { get; set; }
}
public class GroupPatched
{
public Guid Id { get; set; }
public ulong RowVersion { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
[Route("/softwareFeature", "GET", Summary = "Retrieves feature flags for the specified group")]
// [ValidateIsAuthenticated]
public class GetFeatureFlags : QueryDb<FeatureFlag>
{
}
[Route("/softwareFeature/{Id}", "DELETE", Summary = "Deletes a new feature flag for the specified group")]
//[ValidateIsAuthenticated]
public class DeleteFeatureFlag : IDeleteDb<FeatureFlag>, IReturnVoid
{
public Guid Id { get; set; }
}
[Route("/softwareFeature", "POST", Summary = "Creates a new feature flag setting for the specified group")]
//[ValidateIsAuthenticated]
public class CreateFeatureFlag : AuditableRequest, ICreateDb<FeatureFlag>, IReturn<FeatureFlagCreated>
{
public Guid GroupId { get; set; }
public string Name { get; set; }
public bool IsEnabled { get; set; }
}
[Route("/softwareFeature/{Id}", "PATCH", Summary = "Patch an existing feature flag")]
public class PatchFeatureFlag : AuditableRequest, IPatchDb<FeatureFlag>, IReturn<FeatureFlagPatched>
{
public Guid Id { get; set; }
public bool IsEnabled { get; set; }
public string Name { get; set; }
public ulong RowVersion { get; set; }
}
public class FeatureFlagPatched
{
public Guid Id { get; set; }
public ulong RowVersion { get; set; }
}
//In AppHost
Plugins.Add(new AutoQueryFeature
{
MaxLimit = 100,
IncludeTotal = true
});
container.AddSingleton<ICrudEvents>(c =>
new OrmLiteCrudEvents(c.Resolve<OrmLiteConnectionFactory>())
{
});
Plugins.Add(new ValidationFeature());
Plugins.Add(
new AuthFeature(
() => new CustomAuthUserSession(),
new IAuthProvider[]
{
new CustomNetCoreIdentityAuthProvider
{
}
}));