Render different views for different roles just by one action in asp.net mvc - asp.net

Suppose a web application which has three part or so-called three access level:
One for every visitor (just for seeing the content and no need for authentication)
One for Users (Authorized for users)
One for the Administrator (authorized for admin)
now, administrator has access for every content and every operation in the system and Users could do some operations. I don't wanna to create separate areas for Users and Administrator because I don't want to repeat the same code in every area. for example both admin and user can create product, see the list of products, create catalog and... and also every visitor can also sees the list of product, blog posts, ...
So it's not a good idea to separate and make the code duplicated just for separating the tasks. I haven't created any area and I want to control the authentication and authorization by defining the user role when he/she is in the system(ideas!?) but the main issue comes when I want to have separate user interface (views) for users and admin. as I want to use just one Controller for products, Catalog, ... and set authentication and authorization for them, how can I render different view for every request by admin and user? I also don't want to make my code dirty by putting bunch of if/else to define which view to render (I'd rather to duplicate the code in areas!), any solution?

Probably the easiest solution is to write your own RazorViewEngine(Assuming you are using razor).
Then when you want to retrieve a view for a user, you can check the user role and assign the view you want. This is a basic and crude example:
public override ViewEngineResult FindPartialView(
ControllerContext controllerContext,
string partialViewName,
bool useCache)
{
if (controllerContext.User.IsInRole("Admin"))
{
var adminViewLocations = new string[] {"~/AdminViews/" }
return new ViewEngineResult(adminViewLocations);
}
return base.FindPartialView(controllerContext, partialViewName, useCache);
}
Doing this means that all users use the same controllers and authentication, but the views change based on roles (or whatever you want).
You can read more about A Custom View Engine with Dynamic View Location.

Related

How can i do custom authorization in my ASP.NET MVC application

I am making a small SAAS application. I am using the same database for all users and only differentiating between the data using username and ids. This means that the user can type in a new url in the browser and see other users data. This, of course is not a desirable approach. I would like to do a check to see if the current user can actually access the resources: eg.
http://myapplication.com/images/15
And if the user changes the url to
http://myapplication.com/images/16
I should do a check in my database to see if the current user actually has access to see the images with user id 16. And if not redirect to a "not authorized" page.
How do I implement this?
The first step is to make sure that you never have any ID's for the user itself in the url. For instance, never have http://example.com/?user=10. You should always get the users id from their authentication rather than from the URL (or posted values either).
The second step, is to use that ID in your queries. So, for instance, let's say they seek http://example.com/images/100, then in your database you should have a mechanism that links the asset's ownership to the user, either a userid or a mapping table of id's to asset's, etc.. This way, if the user isn't allowed access, it will just return an empty result set. It's impossible for the data to be returned, and the empty result set should tell your page that the item doesn't exist (not necessarily an authorization failure, just that the object doesn't exist).
Third, any pages which are inherently about the user, such as a user profile, account page, or dashboard should never have any ID's at all in the URL, it should just automatically go to the authenticated users page.
Finally, if you need to prevent the user from accessing an entire page or set of pages, then you should do this in the OnAuthorization event or similar (custom attribute, base class, etc..) or using the built-in attribute authorization and use role based authorization. Never do authorization in the PageLoad or similar event (such as the controller action), because by the time you get to that step a lot of work has already happened in the pipeline. It's best to block access long before the page even starts to setup. Authorization events happen at the very beginning of the pipeline.
Make an Action that check userId and returns error page or file
public FileResult Image(string imageName)
{
string UserId = MethodWhereYouGetCurrentUserID();
if(imageName == null) return View("~/Views/Shared/Error.cshtml", (object)"Null image");
string imageShortName = imageName.Split(".")[0];
if(!UserId == imageShortName) return View(~/Views/Shared/Error.cshtml, (object)"You can't access to this");
string path = Server.MapPath("~/Contant/images/"+imageName);
return File(path, "image/jpg");
}
RouteConfig file
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute
(
name: "ImageRoute",
url: "/images/imageName",
default: new {controller = "Home", action = "GetImage"}
);
}

Getting and Displaying AD object properties via a webform

What would be the easiest way to get AD user object properties via a webform based on user input?
To elaborate a bit more this is what I would need:
User enters input to an input field (Employee number - we store it as an extension attribute in AD)
On button click the form returns additional user object properties of the account (such as sAMAccountname, Manager) and displays it on the page (preferably)
I also need to have these properties converted to variables the form can use to pass on to another page sending an e-mail with the retrieved information.
We're using asp for our webforms. So far we only needed to pass user input directly to the mail sender, but this one seems more tricky.
Appreciate any help, thanks!
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
if(user != null)
{
// display the various properties of the "user" object in your web page
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!

ASP.NET MVC Authorisation with CRUD roles

I need the ability to restrict what users can do in my application based on dynamic roles for CRUD.
For example the User/Index would need an authentication such as [ClaimsAuthorize("View", "User")] as oposed to [Authorise(Roles="Administrator")] so that I can check if the user has the security to view.
I have the user roles configured, but what the roles enable users to do is dynamic. An administrator can change the security levels with check boxes that will enable different security groups to do different things.
The main problem is doing this in Razor, I need something similar to #User.CanEditUsers, but I am not sure how I can go about doing this at all.
Any help would be greatly appreciated as I am having trouble finding the correct way to go about this.
Note that Authorizing users to see specific page elements differs from Authorizing for CRUD or other database operations, unless the elements point to operational Actions in Controller. Consider that you may have some elements that there's no need to be saw by a specific user, and don't have specific database operation. Till now we conclude that we need the following permissions :
Permission to See
Permission to Command
I believe that you can use Microsoft Role Provider for both parts. According to MSDN Documentation Considering that :
The Authorize attribute lets you indicate that authorization is
restricted to predefined roles or to individual users. This gives you
a high degree of control over who is authorized to view any page on
the site.
In The next step/question is how to do that?
I think 3 ways are available to meet our purpose:
Solution 1: Creating separate Views with specific page elements due to forwarding each user to related View. In this scenario we must
create separate controller actions too. we have to check user types
before each action like [Authorise(Roles="Administrator")]. We
forced to have static (Pre-defined) Roles and Accessibility. And in
one sentence Not a good solution because of redundancy and
instability.
Solution 2: Creating pages Dynamically simply by adding some if conditions for each access restricted element in One Page(for
example Edit Page). That is like employing #if
(User.IsInRole("Admin")) to authorize specific users and show
related page elements like buttons. In Controller side we can use
if conditions (not as FilterAttribute due to add dynamic
functionality based on generated/added new roles) and control valid
transactions against database. Although FilterAttributes add some great functionalists (like performance optimization). In one sentence A moderate solution.
Solution 3: Act like solution 2, just fix Controller problem by
creating our own custom FilterAttribute for authorization. That will
inherited from AuthorizeAttribute and overrides the OnAuthorize
method to do what you need only for Operations.
For Example :
public class TableAuthorizeAttribute : AuthorizeAttribute
{
public enum TableAction
{
Read,
Create,
Update,
Delete
}
public TableAction Action { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
//do custom authorizization using Action and getting TableEntryID
//from filterContext.HttpContext.Request.QueryString or
//filterContext.HttpContext.Request.Form
}
}
And its usage will be like this :
[TableAuthorize(Action=TableAuthorizeAttribute.TableAction.Update)]
Here is complete example about above concept. Here is complete example for creating dynamic AuthorizeAttribute for authorizing new roles added to application.
Solution 3 in one sentence A perfect but Complex Solution.
Note that by using FilterAttribute before Actions we have limited our application to static/predefined roles. No need to use another Data Structure or generate tables in Database.
You need to separate the concept of roles from groups in your design.
A role gives fixed permissions to perform certain actions in your application. A group is a set of users. What your administrator is really doing is to assign groups of users to different roles.
Your authorization code should be able to rely on fixed roles, e.g. an "ViewUserInfo" role. Then implement the administration interface so that when the admin enables a user to view userinfo, you add that user to the "ViewUserInfo" role.
The same goes with groups: If an entire user group is granted the right to view user info you should add that group to the "ViewUserInfo" role. To introduce the concept of groups and be able to add groups to roles you can't rely on the standard SimpleRoleProvider, so you probably have to implement your own role provider as well as a group provider.
In the end some workaround might be easier, but this is, in my opinion a cleaner architecture.
From the horse's mouth: "Role management helps you manage authorization, which enables you to specify the resources that users in your application are allowed to access. Role management lets you treat groups of users as a unit by assigning users to roles such as manager, sales, member, and so on." (ref: http://msdn.microsoft.com/en-us/library/5k850zwb%28v=vs.100%29.aspx)
Users can be in multiple roles, and you can leverage action filters to get fine-grained control of access to the various resources in your site:
[Authorize(Roles="Contributor, Designer, Reviewer")]
I think the "dynamic" aspect you are after revolves around Administrators being able to add and remove users on-demand from the roles which provide access to those resources, which is pretty typical.
The idea of constantly changing the permissions your roles grant would be a bad design choice.

ASP.Net MVC elegant UI and ModelBinder authorization

We know that authorization's stuff is a cross cutting concern, and we do anything we could to avoid merge business logic in our views.
But I still not find an elegant way to filter UI components (e.g. widgets, form elements, tables, etc) using the current user roles without contaminate the view with business logic. same applies for model binding.
Example
Form: Product Creation
Fields:
Name
Price
Discount
Roles:
Role Administrator
Is allowed to see and modify the Name field
Is allowed to see and modify the Price field
Is allowed to see and modify the Discount
Role Administrator assistant
Is allowed to see and modify the Name
Is allowed to see and modify the Price
Fields shown in each role are different, also model binding needs to ignore the discount field for 'Administrator assistant' role.
How would you do it?
On way I could think to do this is create your own versions of the input extension methods. For example instead of TextBox you could create TextBoxRoles and define it like this:
public static MvcHtmlString TextBoxRoles(
this HtmlHelper htmlHelper,
string name,
string RolesEdit,
string RolesView
)
Then in code it would look like this:
<%= Html.TextBoxRoles("Price", "Administrator","Administrator,Assistant") %>
Then your implementation of TextBoxRoles would check the roles of the current user via User.IsInRole() to determine what should appear on the page.
Of course you would have to do this for every input extension method you use.
Since you already have both the current user and access to the authorization provider in your controllers this is an ideal responsibility for them. Using a naive implementation you might pass a collection of widgets to your view after you filtered which widgets the current user has access to. In the case of your form field, things might get hairy when you consider client side validation.
The binding part would be the most straight forward of all, having a custom binder for these special cases will do the trick specially well since it will have access to the controller context and you can grab the current user from there and bind the values according to your role definitions.
What about something like LinFu, an AOP framework? If it's crosscutting, then declare it is so and treat it as such.

Custom behavior in a web application

I am working on an ASP.NET WebForms project, and we need the ability to configure behavior throughout the application based on the current user's "group". This applies to almost all aspects of the application, including site navigation, showing/hiding certain user controls on pages, and executing custom business logic in some cases. However, the vast majority of the application behavior is shared among groups, so we've ruled out the idea of creating entirely separate apps.
Essentially, what I'm looking for is an architectural approach to implementing custom behavior in an ASP.NET WebForms application. Is there a better approach than sprinkling if/else statements throughout the code base in the view layer, the business layer, and the persistence layer?
Edit: Some examples:
If a user in in Group A, their
navigation will consist of all
navigation from Group B plus a few
additional links.
If a user is in Group A, a page will
show user controls c1, c2, and c3.
If the user is in Group B, they will
only see c1 and c3 on the same page.
If a user saves some data on a form
and they are in Group A, send a
notification email. If the user is
in Group B, send a text message
instead.
We can solve all of these specific problems, but are looking for a way to encapsulate this behavior as much as possible so it's not scattered across the code base.
Edit: There are some interesting answers related to dynamically loading user controls. Should the logic to determine which controls to load or which behavior to use based on the user's group be encapsulated in one (non-cohesive) class, e.g.:
GroupManager.GetNavigationControl(int groupId) // loads site nav control based on group
GroupManager.PerformNotification(int groupId) // sends text or email based on group
Or should this logic exist as close as possible to the location in code where it is used, and therefore be spread across the different layers of the code base?
Well there's not a ton of details to go on here, but I would suspect you might benefit from polymorphism (i.e. various interface implementations) to deal with the parts of the application that differ between user groups. An Inversion of Control container like Spring.NET can help you wire up/configure these various implementations together based on the current user role. You might also benefit from Spring's Aspect Oriented Programming API in which you can decorate methods in your business layer/data access layer so that authorization logic can be executed.
By "Groups" do you mean "Roles"? If you're talking about roles, you can set your behavior by doing something like this
If User.IsInRole("SomeRandomRole") Then
'Do some random behavioral crap
ElseIF User.IsInRole("TheCoolRole") Then
'Do some cool behavioral crap
Else
'Do generic crap
End If
Another option might be to use UserControls based on roles. So when you have a page load, it will load a usercontrol based on the role that requested it.
you could have an PlaceHolder sitting empty and call the LoadControl method from the codebehind.
Then all your user controls would match your roles
Role = Admin | UserControl = Admin.ascx
Role = User | UserControl = User.ascx
Without going into too much detail and going on about IoC and all the like, I think I'd keep it pretty simple and have a plain old factory class that you would use to return the appropriate instantiated UI elements [user controls] based on the current user making the request. In doing this, you will have all of your 'if' statements in one single location. To displense with the 'if' statements you could simply create a mapping config file or DB table that contains references to the user controls to use when a user belongs to a particular group.
Note: Both of these options will result in the creation of dynamic controls on the page which is not without its own complications but I have successfully been using dynamic controls in my apps without issue for a while now - it was just a matter of getting down and dirty with the page life-cycle more than I initially felt comfortable with.
You could also inherit from the Principal object to handle this however you would like.
Here's how I have done it in an application that has custom rules like this:
Created my own IPrincipal object that descended from my "Person" object to be able to inherit the ability to look up groups and roles and such:
public class Principal : MyNamespace.Person, IPrincipal {
}
Make the current context use my IPrincipal object:
protected void Application_AuthenticateRequest(Object Sender, EventArgs E) {
if (HttpContext.Current.User != null &&
HttpContext.Current.User.Identity.IsAuthenticated &&
HttpContext.Current.User.Identity is FormsIdentity) {
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
HttpContext.Current.User = new MyNamespace.Principal(id);
}
}
I then made static methods so that I didn't have to cast every time I wanted to get the current user like this:
public class CurrentUser {
/// <summary>
/// Is the current user authenticated
/// </summary>
static public bool IsAuthed {
get { return System.Web.HttpContext.Current.User.Identity.IsAuthenticated; }
}
/// <summary>
/// Returns the Principal object in case it is needed. Also used for other static properties of this class.
/// </summary>
static public MyNamespace.Principal User {
get {
return (MyNamespace.Principal)System.Web.HttpContext.Current.User;
}
}
}
Then you can call things like CurrentUser.User.IsInGroup().

Resources