User restrictions on views based on customer user properties - asp.net

I'm using ASP.NET MVC 3.
I would like to create an action filter to determine if a user can access a view. I have a User class with properties like IsAdministrator, IsTrusteeUser and IsAuditUser. How would I create an action filter to block certain users if the don't belong in some of these roles?
And aslo how would I use this in my views to hide/display certain controls? I would appreciated some code :)

Why re-invent the wheel?
Put the [Authorize] action filter on the action/controller, specifying the role required:
[Authorize(Roles = "Administrator")]
public ActionResult SomeAdminPage() { // }
Either that, or you could implement your own custom authorization filter by implementing IAuthorizationFilter.

You can implement IActionFilter interface for writing such an attribute extension for Users access permissions checking, a little about coding you can find on
here
To hide/display certain controls on UI, it is not the work of ActionFilters, rather you should either make separate views for each user and redirect him accordingly or do some
If/else
to acheive this.

Related

How to get custom user property in Razor ASP.NET without any ViewModels?

I created my new custom property for User in ASP.NET project ("DarkTheme").
I have a problem (see below). I can access User.Identity.Name without any ViewModels. I can access User.Identity.IsInRole() and so on. But I cannot access my new property ("DarkTheme"). I do not want to use viewmodels (I would have to rewrite the whole application). Is there a way to go to the place where ASP.NET makes User.Identity.Name accessible without any ViewModels and add "DarkTheme" property?
I didn't find the answer to this problem, but I have a workaround.
I used User.IsInRole("DarkTheme") attribute to pass the value to the view (and load different css files depending on the value). It is the only role that user can assign to himself without manager permission.
You could use OnActionExecuted method in your controller in combination with dynamic ViewBag
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (Request.IsAjaxRequest() || filterContext.IsChildAction) return; // you don't need styling for ajax requests which return json
base.OnActionExecuted(filterContext);
YourUser user = ... // get user from db/claims or get theme from cookies etc.;
ViewBag.DarkTheme = user.DarkTheme;
}
and in view it will be invoked simply by #ViewBag.DarkTheme, no namespace needed

ASP.NET MVC 3 - How to restrict areas in an efficient way?

I've got an ASP.NET MVC 3 site with an admin panel (don't we all? :) - I've used my own solution for a very secured login system.
Now, on each view in the admin controller I need to make checks that the user is logged and has the proper authorization, so each time I run the same verification and authorization methods on each view separately.
How could I make the same checks for all the requests to a certain controller? (I mean, right all the checks only once and in one place)
(I also would like to have an exception, so I could allow user to use the login page inside the admin controller and outside of it)
Thanks!
Use an attribute on the controller. Either the standard AuthorizeAttribute (see this) or write your own.
What you're looking for is action filter attributes. They are basically an attribute you can place on a controller that allows you to intercept calls to every action method within a controller and are therefore perfect for security as you can deny/accept requests: http://msdn.microsoft.com/en-us/library/system.web.mvc.actionfilterattribute.aspx
If you want to limit the entire controller instead of the individual actions you could place the [Authorize] attribute like so:
[Authorize]
public class PageController : Controller
{ ... }

User permissions on certain views based on roles

I am using ASP.NET MVC 3. Please excuse my terminology. We assign roles to certain people at work, then we use Windows authentication to determine what roles a user has. Lets say the roles are RoleA, RoleB and RoleC. So now I get a list of roles for a user. Lets says that UserA belongs to RoleA and RoleB. Some of my views need to be authenticated as not everyone can view certain views. Lets say that ViewA can only be viewed by users that belong to roles RoleA and RoleB. How would I do this? What would I need to look into? When a user that does not belong to these roles tries to access the views then he/she should be redirected to an error page.
Also, I need some sort of helper method to check these roles as well to be used in my views to hide/display certain controls. Where is the best place to use this?
Any sample code / articles would be appreciated.
[Authorize(Roles = "RoleA,RoleB")]
public ActionResult Foo()
{
return View();
}
And if you want to check roles in the view:
#if (User.IsInRole("RoleA"))
{
<div>This will be visible only to users in RoleA</div>
}

How can I create a view that has different displays according to the role the user is in?

I want to create a view that has different displays according to the role the user is in.
Should I create a different view for different roles or should I check the roles on the Veiw page itself rather than in the actions?
How would I check the role on the view page?
Or should i use check the roles on the
Veiw page its self rather than on
actions, if so can someone plz show me
how do check that on view page
You need to do both. Check roles on actions as a security measure and check roles on views to enable/disable specific controls.
Within your view page the long form of checking a role is
HttpContext.Current.User.IsInRole("Administrator")
many developers will create page helper methods so you can end up with something more concise for your application like
public static bool IsAdmin(this ViewUserControl pg)
{
return pg.Page.User.IsInRole("Administrator")
}
then in your view you can just use this.IsAdmin()
To keep your view clutter down look into using partial views
<% if (IsAdmin())
{
Html.RenderPartial("AdminPanel");
}
else
{
Html.RenderPartial("UserPanel");
}
%>
If the display changes based on the role -- and the change is small -- then I would do the check in the view. If certain views are restricted based on the role, then I would do the check in the controller. If the views are completely different (this would be hard to imagine), then separate views per role may be appropriate.
You may want to abstract out certain role-specific view components into partial views to simplify your view logic -- basically you only have to check to include the partial or not based on the role.
Also, other than to check for "IsAuthenticated", I would move the role checking logic to the controller and pass (as data) to the view information on which elements to include/exclude based on role. This keeps the actual business logic from bleeding into your view.
If you are using MVC the whole point of development is to keep the logic out of the view and in the controller. It seems to me like you'd be better off on a WebForms development track than an MVC track.
All that being said, I do an Admin check on a lot of my pages by using a check like this:
<% if ((bool)ViewData["Admin"]) { %>
<!-- Show admin controls here -->
<% } %>
But if you are attempting to build actual logic into the View then you need to figure out what you can push back to the controller to do the work and have the view be as dumb as possible, acting on flags sent to it.
without researching the exact mechanism asp.net mvc uses for roles i would scream no for putting any of your business logic in the view which is what you are doing if you are checking roles in the view
Yeah that was something that was bothering me as well ... but at the same time it seems ridiculous to load whole different view for such a small change.
btw
how did you set this up in your controller.
Right now, my controller looks something like the code below, which I don't think is correct.
[Authorize(Roles = "Admin, Member")]
public ActionResult RegistrationInformation()
{
return View();
}
I'm not that familiar with ASP.NET MVC (yet) but can't you do some kind of conditional filter in the View? If the Controller passes the role to the View, then you should be able to do a conditional filter and display a certain block of code if the user is an admin. If you want to display a totally separate page, then you'd have a multiple Views, otherwise you can use one and do some conditional.
In Ruby on Rails it would be something like (sorry, I don't know ASP.NET MVC really yet):
<% if #user.admin? # is the user an admin %>
<h3>Admin Tools</h3>
<% end %>
<p>Regular site content</p>
In Rails you would load the extra content from partials; ASP.NET MVC has something similar but I forget what it's called. Maybe look into that?
Sorry I can't be of more help -- like I said I haven't really gotten to play with ASP.NET MVC.
I have base model which from all others models extend. In this model i have loaded the user's roles. Its based on httpcontext.user.isinrole() method. All views are strong typed expecting the base model type.
So i can always check in all views something like Model.CurrentUser.IsInRoles(Role1 | Role2). Not only in views of course, but in hole application.
I like to have full control over this in the view, and I find that:
<% if (User.IsInRole("Super User")) { %>
<h1>Hello world!</h1>
<% } %>
Works for most scenarios. It also allows you to easily do conditional formatting for other roles, e.g "Content Manager", "Registered", etc.
I do like Todd Smith's answer, because you might change the name of the Admin role, and that will require only one change, whereas, if you put the "Super User" or "Administrator" string directly in the view, you will have to change it wherever you've used the value.

How do you use usercontrols in asp.net mvc that display an "island" of data?

I am trying to find out how to use usercontrols in asp.net mvc. I know how to add a usercontrol to a view and how to pass data to it. What I haven't been able to figure out is how do you do this without having to retrieve and pass the data in every single controller?
For example, if I have a user control that displays the most recent posts on several but not all the pages in the site, how do I write the Controllers so that I get data for that usercontrol and pass it to the user control from only one place in the web site instead of getting and passing data in each of the different controllers that the user control is used in?
I'm not sure if this makes sense or not. Is there a better or recommended way to handle an "island" of data that you want to display on several pages?
I'm coming from web forms where I could just write a user control that got its own data and displayed data independently from the rest of whatever page it is used on.
There are multiple ways to do it.
The basic approach is
Populate the data for the view in the BaseController (OnActionExecuting event)
Writing a custom action filter
Writing an Application Controller (the eg. is in the below links).
An example of OnActionExecuting will be
[HandleError]
public class BaseController : Controller
{
CourseService cs = new CourseService();
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
List<Tag> tags = cs.GetTags();
ViewData["Tags"] = tags;
}
}
You can use the "tags" view data on any view. This is just an example of usercontrol being rendered as side content.
<div id="sidebar_b">
<asp:ContentPlaceHolder ID="ContentReferenceB" runat="server" >
<% Html.RenderPartial("Tags"); %>
</asp:ContentPlaceHolder>
</div>
I found the following URL to be useful.
http://weblogs.asp.net/stephenwalther/archive/2008/08/12/asp-net-mvc-tip-31-passing-data-to-master-pages-and-user-controls.aspx
http://blog.matthidinger.com/2008/02/21/ASPNETMVCUserControlsStartToFinish.aspx
http://www.aaronlerch.com/blog/2008/01/26/displaying-foo-on-every-page-of-an-aspnet-mvc-application/
http://blog.wekeroad.com/2008/01/07/aspnet-mvc-using-usercontrols-usefully/
In the MVC Futures, available on codeplex , contains the RenderAction HtmlHelper extensions. This will allow you to create a controller for the ueser control and this controller will populate the ViewData used by the user control without having to resort to a base controller as was suggested.
In the View you would do
<% Html.RenderAction("Index", "UserControlController") %>
or one of the other overloads.
This will create an instance of the controller, execute the method and render the user control view into the main view. The main view controller does not need to know anything about the user control or its model/data.
Refactor the code that obtains the view data for this user control into it's own method, maybe even it's own model (class). Call this method from each controller that needs to populate the control and pass the results in the ViewData with a well-known key. You might even want to pass the type of the current controller to your method in case it needs to know what data to retrieve based on the base model for the controller.
ViewData["RecentPosts"] = RecentPosts.GetRecentPosts( this.GetType() );
In your control, retrieve the data using the well-known key.
How to Handle "Side Content" in ASP.NET MVC

Resources