Cannot use to decorate attributes
I have been using this successfully and got stuck when trying to use it in an Attribute parameter. Basically I have a class for permissions
public sealed class ToDoSecurityClaims : SecurityClaims<ToDoSecurityClaims>
{
public static readonly ToDoSecurityClaims Complete = new ToDoSecurityClaims("Complete any todo", "todo.complete");
private ToDoSecurityClaims(string name, string value) : base(name, value)
{
}
}
I have a custom AuthorizeAttribute
public MultiAuthorizeAttribute(PolicyComparison comparisonType = PolicyComparison.And, params object[] policies) : base(typeof(MultiAuthorizeFilter))
{
Arguments = new object[] { policies, comparisonType };
}
However when decorating such as;
[MultiAuthorize(PolicyComparison.Or, ToDoSecurityClaims.Complete)]
compiler gives an error Severity "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter". I can use nameof(ToDoSecurityClaims.Complete), but then I have to rename these to match my claim name. So the neat name ToDoSecurityClaims.Complete must be something like ToDoSecurityClaims.Todo_Complete. Basically the name of the claim value and the name itself must be same.
Seems like there is no way around this problem isn't it? Seems like I have to go back to official Enums in this case
You are correct, there is no elegant way around this problem. I was facing the exact same scenario and came up with the following not-so-elegant solution.
Define the values of your claims as constants inside ToDoSecurityClaims. Then use these constants when defining your smart enums:
public sealed class ToDoSecurityClaims : SecurityClaims<ToDoSecurityClaims>
{
public static class Names
{
public const string CompleteName = "todo.complete";
}
public static readonly ToDoSecurityClaims Complete = new ToDoSecurityClaims("Complete any todo", Names.CompleteName);
private ToDoSecurityClaims(string name, string value) : base(name, value)
{
}
}
Next, modify your attribute to accept strings instead of ToDoSecurityClaims. In your constructor, parse the string values into ToDoSecurityClaims.
public MultiAuthorizeAttribute(PolicyComparison comparisonType = PolicyComparison.And, params string[] policies) : base(typeof(MultiAuthorizeFilter))
{
Arguments = policies.Select(ToDoSecurityClaims.FromValue).ToArray();
}
Finally, changed the usage of your attribute to pass in the string constant rather than the ToDoSecurityClaims:
[MultiAuthorize(PolicyComparison.Or, ToDoSecurityClaims.Names.CompleteName)]
Hope this helps!
@mkgn - I just realized that your problem is a little more complicated than I originally thought because your custom attribute has to be able to deal with multiple types of SecurityClaims. I need to rethink my answer.
Sorry for late response. Well, I did it like this;
public sealed class ToDoSecurityClaims : SecurityClaims<ToDoSecurityClaims>{
public static readonly ToDoSecurityClaims todo_complete = new ToDoSecurityClaims("Complete any todo", $"{nameof(todo_complete)}");
public static readonly ToDoSecurityClaims todo_completeself = new ToDoSecurityClaims("Complete owned todos", $"{nameof(todo_completeself)}");
}
Then in controllers I decorate it as;
[HttpPost]
[Route("create")]
[MultiAuthorize(PolicyComparison.Or, nameof(CoreSecurityClaims.resource_create))]
public async Task<IActionResult> Create(ToDoDto todoData){
}
So basically I opted to use nameof().
The other one I am wondering is related to #38 Localization. You have given a link in that thread but I don't understand what you were trying to say.
What I want is to basically be able to translate the description part of enum entry like;
new ToDoSecurityClaims("Complete any todo", $"{nameof(todo_complete)}"); <-- translate "Complete any todo" Since they are defined as static do you have any thoughts about a work around and get them localized?
You have given a link in that thread but I don't understand what you were trying to say.
I think you have me confused with someone else. I did not comment in thread #38