问题
I have a area where the RoleId is kept as a string in the permissions table. I am doing a comparison on the Id to pull all permissions for the Role. I am getting the current Logged in user RoleId like this.
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
string roleid = userManager.FindById(User.Identity.GetUserId()).Roles.Select(r => r.RoleId);
It does not like the usage of string. I am getting
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>' to 'string'
Here is where i am doing the comparison, Note the permission can have either UserId or RoleId, I do not have a problem for the UserId with this setup.
var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl && String.IsNullOrEmpty(i.RoleId = roleid) && String.IsNullOrEmpty(i.UserId = userid));
Is there a different way to get the RoleId or maybe different verbiage to do the compare?
Thanks
Update: Added Controller below. Sorry it is long..
protected override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
try
{
//int roleid = int.Parse(Env.GetUserInfo("roleid"));
//int userid = int.Parse(Env.GetUserInfo("userid"));
string userid = User.Identity.GetUserId();
//string userid = Env.GetUserInfo("userid");
//string roleid = Env.GetUserInfo("roleid");
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
// Select will return collection as opposed to scalar/single value. Pay attention to datatype here.
IEnumerable<string> currentUserRoles = userManager.FindById(User.Identity.GetUserId()).Roles.Select(r => r.RoleId);
//string roleid = roles;
var descriptor = context.ActionDescriptor;
var actionName = descriptor.ActionName.ToLower();
var controllerName = descriptor.ControllerDescriptor.ControllerName.ToLower();
var controller = descriptor.ControllerDescriptor.ControllerName;
var GetOrPost = context.HttpContext.Request.HttpMethod.ToString();
var checkAreaName = context.HttpContext.Request.RequestContext.RouteData.DataTokens["area"];
string AreaName = "";
if (checkAreaName != null)
{
AreaName = checkAreaName.ToString().ToLower() + "/";
}
var cacheItemKey = "AllMenuBar";
var global = HttpRuntime.Cache.Get(cacheItemKey);
if (GetOrPost == "POST")
{
// Added index to string 02/03/2020
// Added add to actonName settings 02/08/2020
///if menupermission create,edit,delete then update value "true" in IsMenuChange file
if (controllerName == "menupermission" && (actionName == "add" || actionName == "index" || actionName == "create" || actionName == "edit" || actionName == "delete" || actionName == "multiviewindex"))
{
global = MenuBarCache(cacheItemKey, global, "shortcache");
}
}
if (global == null)//if cashe is null
{
global = MenuBarCache(cacheItemKey, global, "60mincache");//make cache from db
}
var menuaccess = (MenuOfRole[])global;
if (GetOrPost == "GET")
{
if (actionName == "add" || actionName == "index" || actionName == "create" || actionName == "edit" || actionName == "delete" || actionName == "multiviewindex")
{
// Old Impementation May be removed at Cleanup if not used - 02/10/2020
//ViewBag.Add = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsAdd));
//ViewBag.Read = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsRead));
//ViewBag.Create = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsCreate));
//ViewBag.Edit = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsUpdate));
//ViewBag.Delete = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsDelete))();
// Stack Overflow corrections - 02/10/2020
ViewBag.Add = menuaccess.Any(i => i.MenuURL == controllerName && i.IsAdd);
ViewBag.Read = menuaccess.Any(i => i.MenuURL == controllerName && i.IsRead);
ViewBag.Create = menuaccess.Any(i => i.MenuURL == controllerName && i.IsCreate);
ViewBag.Edit = menuaccess.Any(i => i.MenuURL == controllerName && i.IsUpdate);
ViewBag.Delete = menuaccess.Any(i => i.MenuURL == controllerName && i.IsDelete);
ViewBag.Visable = menuaccess.Any(i => i.MenuURL == controllerName && i.IsVisable);
}
}
string menuUrl = AreaName + controllerName + "/" + actionName;
if (IsActionNameEqualToCrudPageName(actionName))
{
menuUrl = AreaName + controllerName;
}
var checkUrl = menuaccess.FirstOrDefault(i => (i.MenuURL == AreaName + controllerName + "/" + actionName) || i.MenuURL == menuUrl);
///checkUrl: check if menu url Exists in MenuPermission if not exists then will be run
if (checkUrl != null)
{
// Changed below line to use string instead of int.. 01/26/2020
//var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl && String.IsNullOrEmpty(i.RoleId = roleid) && String.IsNullOrEmpty(i.UserId = userid));
// Added change to use roles as collection.
var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl && currentUserRoles.Contains(i.RoleId) && i.UserId == userid);
///check menu && roleid && userid
if (checkControllerActionRoleUserId != null)
{
if (IsActionNameEqualToCrudPageName(actionName))
{
CheckAccessOfPageAction(context, actionName, checkControllerActionRoleUserId);
}
else
{
if (checkControllerActionRoleUserId.IsRead == false || checkControllerActionRoleUserId.IsDelete == false || checkControllerActionRoleUserId.IsCreate == false || checkControllerActionRoleUserId.IsUpdate == false)//if userid !=null && Check Crud
{
UnAuthoRedirect(context);
}
}
}
else
{
var checkControllerActionRole = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl && currentUserRoles.Contains(i.RoleId) && i.UserId == null);
if (checkControllerActionRole != null)
{
if (IsActionNameEqualToCrudPageName(actionName))
{
CheckAccessOfPageAction(context, actionName, checkControllerActionRole);
}
else
{
if (checkControllerActionRole.IsRead == false || checkControllerActionRole.IsDelete == false || checkControllerActionRole.IsCreate == false || checkControllerActionRole.IsUpdate == false)//if userid !=null && Check Crud
{
UnAuthoRedirect(context);
}
}
}
else
{
if (IsThisAjaxRequest() == false)//if userid !=null && Check Crud
{
UnAuthoRedirect(context);
}
}
}
}
}
catch (Exception)
{ }
}
UPDATE: After implementing What @Sam suggested below I also needed to find a way to not give access to users that are not in the permissions table. To avoid redundancy. If a user does not have access to something then i shouldn't need to add it to permissions to make sure they do not have access. I added to a section of below code to redirect to the Dashboard if a user lands on a page they do not have access to.
var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl && currentUserRoles.Contains(i.RoleId)
&& (i.UserId == userid || i.UserId == null) || controllerName == "dashboard"// @Sam: This is how we can combine
);
///check menu && roleid && userid
if (checkControllerActionRoleUserId != null)
{
if (IsActionNameEqualToCrudPageName(actionName))
{
CheckAccessOfPageAction(context, actionName, checkControllerActionRoleUserId);
}
else
{
if (checkControllerActionRoleUserId.IsRead == false || checkControllerActionRoleUserId.IsDelete == false || checkControllerActionRoleUserId.IsCreate == false || checkControllerActionRoleUserId.IsUpdate == false)//if userid !=null && Check Crud
{
UnAuthoRedirect(context);
}
}
}
else
{
UnAuthorizedArea(context);
}
回答1:
There are couple of issues in your code. After fixing the current error you will get more errors:
- You are assigning collection of strings to string (via string roleid). Currently you are getting this error. After fixing this error below errors will come.
The reason why you are getting error is because:
The below statement returns collection of roles (roleId collection to be precise) of logged in user as opposed to single role id.
string roleid = userManager.FindById(User.Identity.GetUserId()).Roles.Select(r => r.RoleId);`And then you are trying to assign this roleid collection to scalar property i.RoleId (via i.RoleId = roleid) in the next statement
var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl && String.IsNullOrEmpty(i.RoleId = roleid) && String.IsNullOrEmpty(i.UserId = userid));`Using assignment operator = instead of
==for comparison. So, you are trying to assign roleid to i.RoleId which is not allowed.Using assignment operator = instead of == for comparison. So, you are trying to assign userid to i.UserId which is not allowed.
Fix: Please modify your roleId section as below:
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
// Select will return collection as opposed to scalar/single value. Pay attention to datatype here.
IEnumerable<string> currentUserRoles = userManager.FindById(User.Identity.GetUserId()).Roles.Select(r => r.RoleId);
(OR)
//You can use var in case you do not know the data types of result.
var currentUserRoles = userManager.FindById(User.Identity.GetUserId()).Roles.Select(r => r.RoleId);
currentUserRoles will contain all the roles of current logged in user. Now use that collection as below (please notice the condition currentUserRoles.Contains(i.RoleId). I also fixed condition around userid.):
var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl
&& currentUserRoles.Contains(i.RoleId) && i.UserId == userid);
Alternatively, above statement can be split using Where and FirstOrDefault as follows:
// Where statement returns collection of menuaccess items meeting all three conditions
var filteredMenuAccessCollection = menuaccess.Where(i => i.MenuURL == menuUrl && currentUserRoles.Contains(i.RoleId) && i.UserId == userid);
// FirstOrDefault will return the first menuaccess item from filteredMenuAccessCollection
var checkControllerActionRoleUserId = filteredMenuAccessCollection.FirstOrDefault();
The above can further be re-written as follows:
var mathingMenuUrlMenuAccessCollection = menuaccess.Where(i => i.MenuURL == menuUrl); // return menuaccess items matching given menuurl
var mathingMenuUrlAndRolesMenuAccessCollection = mathingMenuUrlMenuAccessCollection.Where(i => currentUserRoles.Contains(i.RoleId)); // return menuaccess items matching roles in currentUserRoles
var filteredMenuAccessCollection = mathingMenuUrlAndRolesMenuAccessCollection.Where(i => i.UserId == userid); // return menuaccess items matching given userid
// FirstOrDefault will return the first menuaccess item from filteredMenuAccessCollection
var checkControllerActionRoleUserId = filteredMenuAccessCollection.FirstOrDefault();
To summarize, All 3 condition have to be satisfied to get item from menuaccess collection otherwise null will be returning. The order of conditions evaluation is
- first it tries to find matching menuUrl items from menuaccess collection.
- Then tries to find a menuaccess item where RoleId is contained in currentUserRoles collection.
- Then it tries to find matching userid items from menuaccess collection.
If there are multiple menuaccess items meeting the above 3 conditions then it will return the First item from the menuaccess colletion since we are using FirstOrDefault.
Update: Simplified version of OnActionExecuting:
protected override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
try
{
//int roleid = int.Parse(Env.GetUserInfo("roleid"));
//int userid = int.Parse(Env.GetUserInfo("userid"));
string userid = User.Identity.GetUserId();
//string userid = Env.GetUserInfo("userid");
//string roleid = Env.GetUserInfo("roleid");
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
// Select will return collection as opposed to scalar/single value. Pay attention to datatype here.
IEnumerable<string> currentUserRoles = userManager.FindById(User.Identity.GetUserId()).Roles.Select(r => r.RoleId);
//string roleid = roles;
// @Sam: Added this variable
var actionNamesToCompare = new List<string>{"add", "index", "create", "edit", "delete", "multiviewindex"};
var descriptor = context.ActionDescriptor;
var actionName = descriptor.ActionName.ToLower();
var controllerName = descriptor.ControllerDescriptor.ControllerName.ToLower();
var controller = descriptor.ControllerDescriptor.ControllerName;
var GetOrPost = context.HttpContext.Request.HttpMethod.ToString();
var checkAreaName = context.HttpContext.Request.RequestContext.RouteData.DataTokens["area"];
string AreaName = "";
if (checkAreaName != null)
{
AreaName = checkAreaName.ToString().ToLower() + "/";
}
var cacheItemKey = "AllMenuBar";
var global = HttpRuntime.Cache.Get(cacheItemKey);
if (GetOrPost == "POST")
{
// Added index to string 02/03/2020
// Added add to actonName settings 02/08/2020
///if menupermission create,edit,delete then update value "true" in IsMenuChange file
if (controllerName == "menupermission" && actionNamesToCompare.Contains(actionName))
{
global = MenuBarCache(cacheItemKey, global, "shortcache");
}
}
if (global == null)//if cashe is null
{
global = MenuBarCache(cacheItemKey, global, "60mincache");//make cache from db
}
var menuaccess = (MenuOfRole[])global;
if (GetOrPost == "GET")
{
if (actionNamesToCompare.Contains(actionName))
{
// Old Impementation May be removed at Cleanup if not used - 02/10/2020
//ViewBag.Add = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsAdd));
//ViewBag.Read = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsRead));
//ViewBag.Create = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsCreate));
//ViewBag.Edit = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsUpdate));
//ViewBag.Delete = menuaccess.Where(i => i.MenuURL == controllerName).Select(i => (i.IsDelete))();
// Stack Overflow corrections - 02/10/2020
ViewBag.Add = menuaccess.Any(i => i.MenuURL == controllerName && i.IsAdd);
ViewBag.Read = menuaccess.Any(i => i.MenuURL == controllerName && i.IsRead);
ViewBag.Create = menuaccess.Any(i => i.MenuURL == controllerName && i.IsCreate);
ViewBag.Edit = menuaccess.Any(i => i.MenuURL == controllerName && i.IsUpdate);
ViewBag.Delete = menuaccess.Any(i => i.MenuURL == controllerName && i.IsDelete);
ViewBag.Visable = menuaccess.Any(i => i.MenuURL == controllerName && i.IsVisable);
}
}
// @sam: you can combine menuUrl evaluation like this using ternary operator.
var menuUrl = IsActionNameEqualToCrudPageName(actionName) ? AreaName + controllerName
: AreaName + controllerName + "/" + actionName;
// var checkUrl = menuaccess.FirstOrDefault(i => (i.MenuURL == AreaName + controllerName + "/" + actionName) || i.MenuURL == menuUrl);
// @sam: No need of this if statement
// var checkUrl = menuaccess.FirstOrDefault(i => (i.MenuURL == AreaName + controllerName + "/" + actionName) || i.MenuURL == menuUrl);
///checkUrl: check if menu url Exists in MenuPermission if not exists then will be run
/*if (checkUrl != null)
{
// Changed below line to use string instead of int.. 01/26/2020
//var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl && String.IsNullOrEmpty(i.RoleId = roleid) && String.IsNullOrEmpty(i.UserId = userid));
// Added change to use roles as collection.
// @Sam: Since both if and else are doing same of operations,
// the below if-else can be comibined as follows:
/*var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl &¤tUserRoles.Contains(i.RoleId) && i.UserId == userid);
///check menu && roleid && userid
if (checkControllerActionRoleUserId != null)
{
if (IsActionNameEqualToCrudPageName(actionName))
{
CheckAccessOfPageAction(context, actionName, checkControllerActionRoleUserId);
}
else
{
if (checkControllerActionRoleUserId.IsRead == false || checkControllerActionRoleUserId.IsDelete == false || checkControllerActionRoleUserId.IsCreate == false || checkControllerActionRoleUserId.IsUpdate == false)//if userid !=null && Check Crud
{
UnAuthoRedirect(context);
}
}
}
else
{
var checkControllerActionRole = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl && currentUserRoles.Contains(i.RoleId) && i.UserId == null);
if (checkControllerActionRole != null)
{
if (IsActionNameEqualToCrudPageName(actionName))
{
CheckAccessOfPageAction(context, actionName, checkControllerActionRole);
}
else
{
if (checkControllerActionRole.IsRead == false || checkControllerActionRole.IsDelete == false || checkControllerActionRole.IsCreate == false || checkControllerActionRole.IsUpdate == false)//if userid !=null && Check Crud
{
UnAuthoRedirect(context);
}
}
}
else
{
if (IsThisAjaxRequest() == false)//if userid !=null && Check Crud
{
UnAuthoRedirect(context);
}
}
}//
} */
var checkControllerActionRoleUserId = menuaccess.FirstOrDefault(i => i.MenuURL == menuUrl &¤tUserRoles.Contains(i.RoleId)
&& (i.UserId == userid || i.UserId == null) // @Sam: This is how we can combine
);
///check menu && roleid && userid
if (checkControllerActionRoleUserId != null)
{
if (IsActionNameEqualToCrudPageName(actionName))
{
CheckAccessOfPageAction(context, actionName, checkControllerActionRoleUserId);
}
else
{
if (checkControllerActionRoleUserId.IsRead == false || checkControllerActionRoleUserId.IsDelete == false || checkControllerActionRoleUserId.IsCreate == false || checkControllerActionRoleUserId.IsUpdate == false)//if userid !=null && Check Crud
{
UnAuthoRedirect(context);
}
}
}
}
catch (Exception)
{ }
}
You can test with your data for different users.
来源:https://stackoverflow.com/questions/60173428/getting-aspnet-users-roleid-for-comparison-in-permissions