I am trying to hide a link or would not be able to go to the page if the user is not an administrator. I am able to do the latter using this code in my controller:
[AuthorizeRoles("Admin")]
public ActionResult Registration()
{
return View();
}
When I try to hide the link using this code:
#if (!Context.User.Identity.Name.IsEmpty())
{
<li id="dd_vehicle" class="dropdown">
VEHICLE <b class="caret"></b>
<ul class="dropdown-menu">
#if (ViewContext.HttpContext.User.IsInRole("Admin"))
{
<li id="item_registration">
#Html.ActionLink("Registration", "Registration", "Home")
</li>
}
}
The link gets hidden. But when I login as "Admin", still the link doesn't show.
This is how I AuthorizeAttribute:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
private readonly string[] userAssignedRoles;
public AuthorizeRolesAttribute(params string[] roles)
{
this.userAssignedRoles = roles;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorize = false;
using (var db = new SMBI_DBEntities())
{
var um = new UserManager();
foreach (var roles in userAssignedRoles)
{
authorize = um.IsUserInRole(httpContext.User.Identity.Name, roles);
if (authorize)
return authorize;
}
}
return authorize;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult("~/Home/UnAuthorized");
}
}
and this is in LoginView:
[HttpPost]
public ActionResult Login(UserLoginView ulv, string returnUrl)
{
if (ModelState.IsValid)
{
var um = new UserManager();
var password = um.GetUserPassword(ulv.LoginName);
if (string.IsNullOrEmpty(password))
{
ModelState.AddModelError("", "Login ID and Pasword do not match.");
}
else
{
if (ulv.Password.Equals(password))
{
FormsAuthentication.SetAuthCookie(ulv.LoginName, false);
return RedirectToAction("Registration", "Home");
}
else
{
ModelState.AddModelError("","Password provided is incorrect.");
}
}
}
return View(ulv);
}
Hope you could help. Thank you.
Hi You may try like the below:
#if(Page.User.IsInRole("Admin"))
{
<li id="item_registration">
#Html.ActionLink("Registration", "Registration", "Home")
</li>
}
Helpful link:How to use Page.User.IsInRole
And just as an additional info, you can also write helper like below for the future purpose if required
public static class PrincipalExtensions
{
public static bool IsInAllRoles(this IPrincipal principal, params string[] roles)
{
return roles.All(r => principal.IsInRole(r));
}
public static bool IsInAnyRoles(this IPrincipal principal, params string[] roles)
{
return roles.Any(r => principal.IsInRole(r));
}
}
Now simply you could call this extension method like this:
// user must be assign to all of the roles
if(User.IsInAllRoles("Admin","Manager","YetOtherRole"))
{
// do something
}
// one of the roles sufficient
if(User.IsInAnyRoles("Admin","Manager","YetOtherRole"))
{
// do something
}
Source: https://stackoverflow.com/a/32385065/3397630
Thanks
Related
In my AdministratorController I have an action with custom attribute:
[AuthorizedOnly (Roles = "admin, superadmin")]
public ActionResult Index()
{...}
The attribute is:
class AuthorizedOnlyAttribute : AuthorizeAttribute
{
public AuthorizedOnlyAttribute()
{
View = "~/Views/Main/Index.cshtml";
Master = String.Empty;
}
public String View { get; set; }
public String Master { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
CheckIfUserIsAuthenticated(filterContext);
}
private void CheckIfUserIsAuthenticated(AuthorizationContext filterContext)
{
if(filterContext.Result == null)
return;
if(filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if(String.IsNullOrEmpty(View))
return;
var result = new ViewResult{ViewName = View, MasterName = Master};
filterContext.Result = result;
}
}
It correctly shows me the view that I need: ~/Views/Main/Index.cshtml
But in my browser URL is still from Administrator controller: .../Administrator/Index
How can I redirect to the View that I need, so that URL would also change?
Thanks a lot in advance!
Try this
string retUrl = filterContext.HttpContext.Request.RawUrl;
filterContext.Result =
new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary
{{ "controller", "Main" },
{ "action", "Home" },
{ "returnUrl", retUrl } });
Is it possible to make a filter that, after a controller action has been (mostly) processed, checks for a certain test condition and routes to a different view transparently to the user (i.e., no change in the URL)?
Here would be my best guess at some pseudocode:
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
// If some condition is true
// Change the resulting view resolution to XYZ
base.OnResultExecuting(filterContext);
}
filterContext.Result = new ViewResult
{
ViewName = "~/Views/SomeController/SomeView.cshtml"
};
This will short-circuit the execution of the action.
also you can return view as from your action
public ActionResult Index()
{
return View(#"~/Views/SomeView.aspx");
}
This is what I ended up doing, and wrapped up into a reusable attribute and the great thing is it retains the original URL while redirecting (or applying whatever result you wish) based on your requirements:
public class AuthoriseSiteAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
// Perform your condition, or straight result assignment here.
// For me I had to test the existance of a cookie.
if (yourConditionHere)
filterContext.Result = new SiteAccessDeniedResult();
}
}
public class SiteAccessDeniedResult : ViewResult
{
public SiteAccessDeniedResult()
{
ViewName = "~/Views/SiteAccess/Login.cshtml";
}
}
Then just add the attribute [SiteAccessAuthorise] to your controllers you wish to apply the authorisation access to (in my case) or add it to a BaseController. Make sure though the action you are redirecting to's underlying controller does not have the attribute though, or you'll be caught in an endless loop!
I have extended the AuthorizeAttribute of ASP.NET MVC action filter as DCIMAuthorize, in which I perform some security checks and if user is not authenticated or authorized then action filter will take user to access denied page. My implementation is as below:
public class DCIMAuthorize : AuthorizeAttribute
{
public string BusinessComponent { get; set; }
public string Action { get; set; }
public bool ResturnJsonResponse { get; set; }
public bool Authorize { get; set; }
public DCIMAuthorize()
{
ResturnJsonResponse = true;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
try
{
//to check whether user is authenticated
if (!httpContext.User.Identity.IsAuthenticated)
return false;
//to check site level access
if (HttpContext.Current.Session["UserSites"] != null)
{
var allSites = (VList<VSiteList>)HttpContext.Current.Session["UserSites"];
if (allSites.Count <= 0)
return false;
}
else
return false;
// use Authorize for authorization
Authorize = false;
string[] roles = null;
//get roles for currently login user
if (HttpContext.Current.Session["Roles"] != null)
{
roles = (string[])HttpContext.Current.Session["Roles"];
}
if (roles != null)
{
//for multiple roles
string[] keys = new string[roles.Length];
int index = 0;
// for each role, there is separate key
foreach (string role in roles)
{
keys[index] = role + "-" + BusinessComponent + "-" + Action;
index++;
}
//access Authorization Details and compare with keys
if (HttpContext.Current.Application["AuthorizationDetails"] != null)
{
Hashtable authorizationDetails = (Hashtable)HttpContext.Current.Application["AuthorizationDetails"];
bool hasKey = false;
foreach (var item in keys)
{
hasKey = authorizationDetails.ContainsKey(item);
if (hasKey)
{
Authorize = hasKey;
break;
}
}
}
}
return base.AuthorizeCore(httpContext);
}
catch (Exception)
{
throw;
}
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
try
{
filterContext.Controller.ViewData["ResturnJsonResponse"] = ResturnJsonResponse;
base.OnAuthorization(filterContext);
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
return;
}
if (!Authorize)
{
//Authorization failed, redirect to Access Denied Page
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary{{ "controller", "Base" },
{ "action", "AccessDenied" }
//{ "returnUrl", filterContext.HttpContext.Request.RawUrl }
});
}
}
catch (Exception)
{
throw;
}
}
}
You Can Also Save All Route File Path in a Static And Use it Like This :
public static class ViewPath
{
public const string SomeViewName = "~/Views/SomeViewName.cshtml";
//...
}
And into Your ActionFilter :
context.Result = new ViewResult()
{
ViewName = ViewPath.SomeViewName /*"~/Views/SomeViewName.cshtml"*/
};
Ok following up with this thread, here's what I came up with...
public class SharweAuthorizeAttribute : AuthorizeAttribute
{
private bool isAuthenticated = false;
private bool isAuthorized = false;
public new string[] Roles { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (SessionManager.CheckSession(SessionKeys.User) == true)
{
isAuthenticated = true;
foreach (string role in Roles)
{
if (RolesService.HasRole((string)role))
isAuthorized = true;
}
}
return (isAuthenticated && isAuthorized);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (!isAuthenticated)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "action", "User" },
{ "controller", "Login" }
});
} else if(!isAuthorized) {
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "action", "Home" },
{ "controller", "Error" }
});
}
}
}
How/why I came up with this? Because I believe the AuthorizeAttribute workflow goes as follows:
First, AuthorizeCore is triggered. If it returns true, the user is authorized. If it returns false, HandleUnauthorizedRequest is triggered. Is that right?
I read somewhere that I need to use the new keyword to override a property. Therefore, this is how I overrode the Roles property. But what if the overriding property was of a different type of the initial one (the one in the base class), does that also hide it or creates a totally different property?
So what do you think? Should that actually work? I cannot test it now because I haven't set up the UI (waiting for the designer to get done with the design)... In fact, this is the first time I appreciate the benefits of TDD, I used to think it's utterly stupid and useless, but I was wrong :)
P.S: On this thread, #tvanfosson is setting the CachePolicy of the context (I think), could someone explain that and why I might need to do that please?
Thanks in advance.
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private readonly bool _authorize;
private readonly string[] _roles;
public CustomAuthorizeAttribute(string roles)
{
_authorize = true;
_roles = roles.Split(',');
}
public CustomAuthorizeAttribute(string roles, bool isAdminPath)
{
_authorize = true;
_roles = roles.Split(',');
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//if controller have role auth and user is not loged
if(_authorize && !httpContext.User.Identity.IsAuthenticated)
return false;
// if controller have role auth and user is loged
if(_roles != null)
{
//grab user roles from DB
var UserRole = RoleRepository.GetUserRole(new Guid(httpContext.User.Identity.Name));
if (_roles.Contains(UserRole))
return true;
}
return false;
}
}
In Controller
[CustomAuthorize("Administrator,Company,OtherRole")]
public ActionResult Test(){
return View();
}
I have the following code:
[AcceptVerbs(HttpVerbs.Post), Authorize(Roles = RoleKeys.Administrators)]
public ActionResult Edit(int id, FormCollection collection)
{
User user = userRepository.GetUser(id);
try
{
this.UpdateModel(user);
userRepository.Save();
return this.RedirectToAction("Details", new { id = user.UserId });
}
catch
{
this.ModelState.AddModelErrors(user.GetRuleViolations());
return View(new UserFormViewModel(user));
}
}
If the currently logged in user is not in the Administrators role, it kicks them back to the login screen. The user is already logged in, they are just not authorize to perform the requested action.
Is there any way to have them redirected to a specific view, for example, AccessDenied?
You can define your own attribute:
public class MyAuthorizeAttribute: AuthorizeAttribute
{
public override void OnAuthorization( AuthorizationContext filterContext )
{
base.OnAuthorization(filterContext);
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "controller", "Login" },
{ "action", "AccessDenied" }
});
}
}
}
and use
[AcceptVerbs(HttpVerbs.Post), MyAuthorize(Roles = RoleKeys.Administrators)]
I wish to lock out access to a user's EDIT page (eg. /user/pure.krome/edit) if
a) Identity.IsAuthenticated = false
or they are authenticated but
b) Idenitity.Name != user name of the user page they are trying to edit
c) Identity.UserType() != UserType.Administrator // This is like a Role, without using RoleProviders.
I'm assuming u can decorate a controller or a controller's action method with something(s), but i'm just not sure what?
Look at the AuthorizeAttribute.
ASP.Net MVC: Can the AuthorizeAttribute be overriden?
A custom attribute derived from AuthorizeAttribute is what I use to do this. Override the OnAuthorize method and implement your own logic.
public class OnlyUserAuthorizedAttribute : AuthorizeAttribute
{
public override void OnAuthorize( AuthorizationContext filterContext )
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizeResult();
}
...
}
}
I implemented the following ActionFilterAttribute and it works to handle both authentication and roles. I am storing roles in my own DB tables like this:
User
UserRole (contains UserID and RoleID foreign keys)
Role
public class CheckRoleAttribute : ActionFilterAttribute
{
public string[] AllowedRoles { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string userName = filterContext.HttpContext.User.Identity.Name;
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (AllowedRoles.Count() > 0)
{
IUserRepository userRepository = new UserRepository();
User user = userRepository.GetUser(userName);
bool userAuthorized = false;
foreach (Role userRole in user.Roles)
{
userAuthorized = false;
foreach (string allowedRole in AllowedRoles)
{
if (userRole.Name == allowedRole)
{
userAuthorized = true;
break;
}
}
}
if (userAuthorized == false)
{
filterContext.HttpContext.Response.Redirect("/Account/AccessViolation", true);
}
}
else
{
filterContext.HttpContext.Response.Redirect("/Account/AccessViolation", true);
}
}
else
{
filterContext.HttpContext.Response.Redirect(FormsAuthentication.LoginUrl + String.Format("?ReturnUrl={0}", filterContext.HttpContext.Request.Url.AbsolutePath), true);
}
}
I call this like this...
[CheckRole(AllowedRoles = new string[] { "admin" })]
public ActionResult Delete(int id)
{
//delete logic here
}