I want to create a AuthorizeAttribute
that gets the current ActionMethod
RouteData
and searches in a database for a user that has access to this ActionMethod
.
I created a UserAccessPermission
table:
public class UserAccessPermission
{
[Key]
public int UserAccessPermissionId { get; set; }
public string ActionMethod { get; set; }
public string Controller { get; set; }
public string Area { get; set; }
public bool HasAccess { get; set; }
[DisplayName("User ID")]
[ForeignKey("ApplicationUser")]
public string Id { get; set; }
[DisplayName("User")]
public virtual ApplicationUser ApplicationUser { get; set; }
}
and then link it to the User
table:
public class ApplicationUser : IdentityUser
{
public ApplicationUser()
{
AccessPermissions = new HashSet<UserAccessPermission>();
}
some custome field
//*******************************************************************
public virtual ICollection<UserAccessPermission> AccessPermissions { get; set; }
}
so each user has multi ActionMethod
that can access it. Then I create my custom AuthorizeAttribute
:
public class DynamicRoleAuthorizeAttribute : AuthorizeAttribute
{
private readonly UserManager<ApplicationUser> _userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool result = false;
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
//var rolesProvider = new RoleProvider();
var routeData = httpContext.Request.RequestContext.RouteData;
var controller = routeData.GetRequiredString("controller");
var action = routeData.GetRequiredString("action");
string area = null;
var userId = httpContext.User.Identity.GetUserId();
var _user = _userManager.FindById(userId);
if (routeData.DataTokens["area"] != null)
{
area = routeData.GetRequiredString("area");
result = _user.AccessPermissions.Where(x => x.Controller.Equals(controller) && x.ActionMethod.Equals(action) && x.Area.Equals(area)).Select(x => x.HasAccess).FirstOrDefault();
}
else
{
result = _user.AccessPermissions.Where(x => x.Controller.Equals(controller) && x.ActionMethod.Equals(action)).Select(x => x.HasAccess).FirstOrDefault();
}
if (result)
{
return true;
}
return false;
//return base.AuthorizeCore(httpContext);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
But this approach is too hard for page management and the admin should give user access permission for each ActionMethod
. Is there any better way to do this?