I'm using OAuth2.0 Owin (password grant) in my WebAPI.My initial token Response is like below
{
"access_token": "_ramSlQYasdsRTWEWew.....................",
"token_type": "bearer",
"expires_in": 17999,
"permissions": {
"user": [
"Add",
"Update",
"Delete"
],
"Product": [
"Read",
"Create"
]
}
}
I've customized the response by creating a new Key called permissions
which hold the privileges for the corresponding user.
From here I need to validate each Request from my Resource server
,by checking whether the user has enough permissions to call the API using Authorize Attribute.
I found a similar example from here where it deals with Dot net Core, which is not suitable for my case.
The difficult part is that the permission
JSON Key is itself making a complex with ArrayList
[CustomAuthorize(PermissionItem.Product, PermissionAction.Read)]
public async Task<IActionResult> Index()
{
return View(Index);
}
public class CustomAuthorize : AuthorizeAttribute {
public AuthorizeAttribute (PermissionItem item, PermissionAction action) {
//Need to initalize the Permission Enums
}
public override void OnAuthorization (HttpActionContext actionContext) {
//Code to get the value from Permissions ArrayList and compare it with the Enum values
}
}
The above is the idea I'm having. But due to the complexity of the Permissions
Key and Enum comparison I'm couldn't able to move forward.
Also, there is a question like If the permission for User is Add as well as Update means I need to create two Attribute conditions before my Controller.
Like
[CustomAuthorize(PermissionItem.User, PermissionAction.Add)]
[CustomAuthorize(PermissionItem.User, PermissionAction.Update)]
Which leads to adding more lines of Attributes. So Is there is any way to make it as in a single Conditions with |
separated?
[CustomAuthorize(PermissionItem.User, PermissionAction.Update|PermissionAction.Add)]
Why don't you allow your CustomAuthorize constructor to have multiple Permission actions.
public class CustomAuthorize : AuthorizeAttribute
{
private readonly PermissionAction[] permissionActions;
public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
{
this.permissionActions = permissionActions;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
var currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
if (!currentIdentity.IsAuthenticated) {
// redirect to access denied page
}
var userName = currentIdentity.Name;
// step 1 : retrieve user object
// step 2 : retrieve user permissions
// step 3 : match user permission(s) agains class/method's required premissions
// step 4 : continue/redirect to access denied page
}
}
And you'll annotate your class with:
[CustomAuthorize(PermissionItem.User, PermissionAction.Update, PermissionAction.Add)]
I'm not sure, what does OP want to achieve here. If you are relying on HTTP request to provide access rights then that is A BIG SECURITY HOLE. On each request you should retrieve user's access right information from the database and then match is against the required permission of the class/method.
As a rule of thumb you should not rely on request object to tell you what are the permissions that current user have. You should retrieve them from the datastore.
My Implementation of CustomAttribute
public class CustomAuthorize : System.Web.Http.AuthorizeAttribute
{
private readonly PermissionAction[] permissionActions;
public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
{
this.permissionActions = permissionActions;
}
protected override Boolean IsAuthorized(HttpActionContext actionContext)
{
var currentIdentity = actionContext.RequestContext.Principal.Identity;
if (!currentIdentity.IsAuthenticated)
return false;
var userName = currentIdentity.Name;
using (var context = new DataContext())
{
var userStore = new UserStore<AppUser>(context);
var userManager = new UserManager<AppUser>(userStore);
var user = userManager.FindByName(userName);
if (user == null)
return false;
foreach (var role in permissionActions)
if (!userManager.IsInRole(user.Id, Convert.ToString(role)))
return false;
return true;
}
}
}