Reputation: 417
I'm facing an issue while working with Role-Based authentication for web APi.
I have a controller class where the controller has a custom authorize attribute called Myauthorize. I have a method inside the controller which can be accessed only with Admin access. But the same method has been calling with QA access as well. Could anyone please help with the below?
Please find the code below. Controller :
namespace Hosiptal.Controllers.office
{
[MyAuthorize(Constants.Roles.Admin)]
public class UserRolesController : ApiController
{
private readonly IRepository<EntityModels.Role> rolesRepository;
public UserRolesController(IRepository<EntityModels.Role> rolesRepository)
{
this.rolesRepository = rolesRepository;
}
// GET: Users
[HttpGet]
[Route("")]
public IEnumerable<Role> GetAll()
{
return this.rolesRepository.GetAll()
.ToArray()
.Select(r => Mapper.Current.Get<Role>(r));
}
}
}
MyAuthorize has followed.
namespace Hospital.Web.Filters.WebApi
{
public class MyAuthorize: AuthorizeAttribute
{
private readonly string[] allowedroles;
private static IUserProfileRepository UserProfileRepository
{
get { return IoC.Current.Resolve<IUserProfileRepository>(); }
}
public MyAuthorize(params string[] roles)
{
this.allowedroles = roles;
}
public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken
cancellationToken)
{
var claimsIdentity = actionContext.RequestContext.Principal.Identity as ClaimsIdentity;
var alias = claimsIdentity.Name.Split('@')[0];
if (alias == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
user(alias);
return base.OnAuthorizationAsync(actionContext, cancellationToken);
}
public static GenericPrincipal user(string userName)
{
userName = userName.ToUpper();
var userProfile = UserProfileRepository.Get(userName) ?? new UserProfile()
{
UserName = userName,
Roles = new List<Role>(),
FirstLoginDateUtc = DateTime.UtcNow
};
return CreatePrincipal(userProfile);
}
public static GenericPrincipal CreatePrincipal(UserProfile user)
{
var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name,
user.UserName) }, "Custom");
return new GenericPrincipal(identity, user.Roles.Select(i =>
i.Name).ToArray());
}
}
}
How can restrict the user here based on access level?
Upvotes: 1
Views: 2687
Reputation: 7783
If you review the source code for the AuthorizeAttribute
class, you will see that it uses the controller context request's principal to perform authorization, so override the IsAuthorized
method instead, move your code there and assign the principal you create to the context request's principal:
protected override bool IsAuthorized(HttpActionContext actionContext)
{
var claimsIdentity = actionContext.RequestContext.Principal.Identity as ClaimsIdentity;
var alias = claimsIdentity.Name.Split('@')[0];
if (alias == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
//This sets the context's principal so the base class code can validate
actionContext.ControllerContext.RequestContext.Principal = user(alias);
//Call the base class and let it work its magic
return base.IsAuthorized(actionContext);
}
I will refrain from commenting on the design itself. This should fix your issue.
Upvotes: 1
Reputation: 3473
You don't need to create your own authorize filter for this.
Use the built-in [Authorize(Roles = "Admin")]
- which will check if the user has a claim called "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" and if that value matches to the one you put in that authorize attribute, the authorization will succeed.
So in your case just make sure, when you log in the user to set his claim with the role like this:
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Role, "Admin"), //here set the users role
// ... other claims
};
(ClaimTypes
class is from the namespace System.Security.Claims
)
And then the [Authorize(Roles = "Admin")]
should work just fine
Upvotes: 0
Reputation: 1529
This is what's working for me
public class AdminAuthorizeAttributee : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (AuthorizeRequest(actionContext))
{
return;
}
HandleUnauthorizedRequest(actionContext);
}
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
base.HandleUnauthorizedRequest(actionContext);
}
private bool AuthorizeRequest(HttpActionContext actionContext)
{
try
{
var username = HttpContext.Current.User.Identity.Name;
var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = userManager.Users.Where(a => a.UserName == username).FirstOrDefault();
var rolesForUser = userManager.GetRoles(user.Id);
var role = "Admin";
if (rolesForUser.Contains(role))
{
return true;
}
return false;
}
catch (Exception ex)
{
return false;
}
}
}
and in Controller
[AdminAuthorizeAttributee]
public class YOUR_Controller : ApiController
Upvotes: 0