Statically I set access to my services like so:
[Authenticate]
public class AppUserService : Service
{
[RequiredRole("Administrator")]
public object Post(CreateAppUser request)
{
//.....
}
}
How can I do this programmatically?
I will let the user create roles using a GUI. Then I will present a list of available methods, e.g. by providing the methods using improved code like:
var appHost = HostContext.AppHost;
var restPaths = appHost.RestPaths;
foreach (var restPath in restPaths)
{
var reqType = restPath.RequestType;
string verbs = string.Empty;
if (restPath.Verbs != null)
{
var counter = 0;
foreach (var verb in restPath.Verbs)
{
if (counter > 0) verbs += ", ";
verbs += verb;
counter++;
}
}
Debug.WriteLine($"Path: {restPath.Path} | Verbs: {verbs} | Name: {reqType.Name} FullName: {reqType.FullName}");
}
The code above outputs something like
Path: /appusers | Verbs: POST | Name: CreateAppUser FullName: MyServer.ServiceModel.DTOs.Request.CreateAppUser
So I could show in my UI the Name property of the RequestType and let him define, what roles are allowed to call this method. So the user may create a role called 'User Management' and allow members of this role to execute CreateAppUser.
Using annotations I would write
[RequiredRole("Administrator", "User Management")]
public object Post(CreateAppUser request)
{ .... }
Is this anyhow possible in C# code?
ServiceStack does have a way to dynamically Add Attributes at runtime, e.g:
typeof(CreateAppUser)
.AddAttributes(new RequiredRoleAttribute("Administrator", "User Management"));
Which is an alternative to declaring attributes statically, but it's still not a solution for a data-driven authorization system.
But you could add your own custom Authorization logic in addition to ServiceStack's built-in attributes by validating it in your Service:
public ICustomAuth CustomAuth { get; set; }
public object Post(CreateAppUser request)
{
var session = base.GetSession();
var requiresRoles = CustomAuth.GetRequiredRoles(request.GetType());
var hasAllRoles = requiresRoles.All(r =>
session.HasRole(r, base.AuthRepository))
if (!hasAllRoles)
throw new UnauthorizedAccessException("Requires all roles");
}
If you do this a lot you will want to refactor the custom validation logic into a single reusable method, or if you prefer into a custom RequestFilter attribute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With