Share an object application-wide in ASP.NET MVC3 - c#

I have an ASP.NET MVC3 web application with C# and Razor.
Through a form in a View I get the Context.User.Identity.Name submitted to an action method in a Controller A.
I would like to have available this variable application-wide (between multiple controllers).
Now I am just able to assign it to a global variable _UserName within the Controller A, but of course it is not available in Controller B.
Is it possible to do that?
Thanks
Francesco

If you are accessing this in any controller, you should use HttpContext.User.Identity in your controller methods - it will be available there. No need to store in the session.

Create a parent controller from which all your controllers inherit from and set the variable there. You could do a number of things with it from there--wrap it in a view model, put some user details into the ViewBag, etc
public class UserController : Controller
{
// create your own User class with as many properties as you need
protected User user { get; set; }
public UserController()
{
user = // get user from db, wherever
}
}
Then, just inherit from UserController
public class ControllerA : UserController
{
public ActionResult DoSomething()
{
user.Property = 123;
}
}

You should look into caching and possibly using the users session store this information.
Check out this question.

Related

Global authorization rule for a role

I have MVC application with fixed set of roles: Admin, Management, Student
One of the new roles (Student) should have limited access to the application.
I have lot of methods and don't want to write [Authorize(... attribute for each of them.
Is there a way to define them once for all of the methods?
It's possible to define Authorize attribute also on a controller.
To define it only once I can use BaseController. When I have one common controller, that every other controller inherits from I can write this:
[Authorize(Roles = "Administrator, Management")]
public abstract class BaseController : Controller
{...
Then in some other controller:
public class ClassController : BaseController
{
...
[Authorize(Roles = ("Administrator, Management, Student"))]
public ActionResult Method()
{
...
This will ensure that role Student will have access only to the Method and not any other method defined in any of the controllers.

Get URL of current page in C# with AngularJS

I am working on tracking system for my SignalR Hub purpose. For this I have class where I want to store URL which will represent current page where user is, then his last request since I use paged list for my data tables and I need to know exactly on which page user is and of course user id.
This is my class where I want to store information
public class UserTracking
{
public string URL { get; set; }
public string LastRequest { get; set; }
public string UserId { get; set; }
}
Since I have a single page application I have problem with tracking user position on website because of angular routing, but for displaying views I have dashboard controller with ActionResults methods to allow me to display .cshtml pages with angular routing, something like this below
public ActionResult ProjectTask()
{
return View();
}
public ActionResult Project()
{
return View();
}
My question is if I am able somehow to get URL of user position on my website. For example if user is on http://localhost:2969/Dashboard#/tasks/ I want to get this /Dashboard#/tasks. Maybe I can get some information from my ActionResults, but I have no idea how.
It is hard to know if this will work for you with the information you've provided, but the following could work.
If you know the specific routes that a user must navigate to to reach you MVC Controller then you could pass in that information as a model when you return the view. Say I have an MVC route that is meant to return a Razor page that displays all the items from my list named "Freddy's Birthday". The URL in this case would look something like:
localhost/list/Freddy's%20Birthday
matching a route:
[Route("~/list/{id}")]
To inform Angular of what you're dealing with, simply pass in the information as a model:
public ActionResult List(string id)
{
return View(model: id);
}
You can access that model in your cshtml with #Model. If the id passed in was "Freddy's Birthday" like before:
<div todo-list-item-directive>#Model</div>
Would return from ASP as:
<div todo-list-item-directive>Freddy's Birthday</div>
This way works, and you could build some view models to reference in your Razor pages if you need to pass in more complicated information. However, if at all possible, it'd likely be worth your while to set up ui-router and use Angular for your view routing and ASP.NET for your API.

Will an MVC model used as a field in a controller be overwritten on each request?

Have a currious situation where a colleague wrote some code, and now when multiple people access the page she constructed, the site will overwrite User A's model data with User B's model data, if user B comes in and starts a census after User A.
Is it the fault of the model being used as a field in the controller? She originally had it static, which horrified me, so she changed it to non static field, but something still seems off to me.
namespace App.Controllers
{
public class HomeController : Controller
{
private Census _census = new Census();
public ActionResult UploadCensus()
{
return View(_census);
}
[HttpPost]
public ActionResult UploadCensus()
{
if (ModelState.IsValid)
{
// Save Census Model to Database
}
}
}
}
I've never used models this way, because I pass them back and forth from view to view, but wanted to see if anybody had any ideas.
Per Ben Robinson this is the correct answer.
Yes you get a controller instance per request so any instance fields will be specific to that instance and request. Static fields will remain but be shared across app domain so each request will be writing to /reading from the same shared field. So this would account for the overwriting behaviour you have observed.

How can Views and ViewModels utilize claims-based authorization in MVC 5?

In my project I have implemented ASP.NET Identity 2.x with claims based authorization plus authentication.
I have added added support for a claims authorization attribute as described here.
Here are the claims I'va come up with that would allow/disallow CRUD on employees.
public class ResourceClaimTypes
{
public const string CreateEmployee = "urn:company:Employee:Create";
public const string ReadEmployee = "urn:company:Employee:Read";
public const string UpdateEmployee = "urn:company:Employee:Update";
public const string DeleteEmployee = "urn:company:Employee:Delete";
}
An action would look like this:
[ClaimsAuthorize( ResourceClaimTypes.ReadEmployee )]
public ActionResult Index()
{
return View();
}
What I don't quite understand is how to make use of those claims in a view and its view model.
For instance, there is a view for displaying employees, which is a simple grid.
Then there are views for editing and creating employees.
What the view and view model should be capable of doing now is hiding or showing the Save/Update/Delete buttons according to the user's claims.
Approach on the views:
Index -> should display all employees if ReadEmployee claim is present, otherwise the view should still be accessible, but with a message "No premission to view employees".
Create/Edit -> the user should still be able to nvaigate to these views, but the "Create"/"Save" buttons should not be visible.
Delete -> all "Delete" buttons should be hidden.
Bottom line is, views should be accessible, but the Create/Save buttons should be hidden.
How can that be done?
* UPDATE / MY SOLUTION *
This is how I ended up doing it.
Following Derek's suggestion I have used Action/Resource based authentication. Along with ASP.NET Identity I have implemented the IUserClaimStore interface to grab the claims from the DB.
The Views and ViewModels (!) do NOT contain ANYTHING like CanRead, CanWrite!
I am using KendoUI and have created an extension method for buttons.
Inside the extension method I can access the custom ResourceAuthorizationManager (see blog from Dominik Baier). So when creating the button, I can call HttpContaxtBase.CheckAccess(...) to determine if the button should be enabled/visible, or not.
The only thing I need is a way to tell the extension method what action/resource combination to check access for.
Razor Example:
#Html.LinkButton(Action.Create, Resource.Employee)
This is all that is needed in the view to display (or not) a button that says "Create" and points to the Create view of the Employee controller.
Very clean, IMHO.
You should look at a product of Dominic Baier at Thinktecture for something like this.
The following article will explain how to achieve what your looking for quite elegantly.
http://leastprivilege.com/2014/06/24/resourceaction-based-authorization-for-owin-and-mvc-and-web-api/
They have example in there Git Hub repo.
** EDIT **
Here is the link to the GitHub Example you need to follow.
https://github.com/IdentityModel/Thinktecture.IdentityModel/tree/master/samples/OWIN/ResourceAuthorization/Chinook
You have access current user's claims everywhere in your project and views are not an exception. Simply cast current user's identity to claimsIdentity to access user's claims:
var claims= ((ClaimsIdentity)HttpContext.Current.User.Identity).Claims;
You could write an extension method for this also:
public static bool CanEdit(this IIdentity identity)
{
return identity.IsAuthenticated
&& identity is ClaimsIdentity
&& ((ClaimsIdentity)identity).HasClaim(x =>
x.Type == "EditClaim" && x.Value == "true");
}
Then you could easily write this code:
if(HttpContext.Current.User.Identity.CanEdit())
{
//your code
}
But even you could check claims in views directly, consider check claims in your controllers and send simple true or false values by view models to your views for better approach.
Since we do not want mix our logic to views. It is much better to check privileges in controller instead. Consider this:
class PrivilegesViewModel
{
public bool CanEdit{get;set;}
public bool CanRead{get;set;}
// and so on
}
class PostViewModel
{
// our model data
public PrivilegesViewModel Privileges{get;set;}
}
And in your controller:
public ActionResult Edit(int id)
{
PostViewModel model=_postManager.Get(id);
model.Privileges=new PrivilegesViewModel
{
CanEdit=HttpContext.Current.User.Identity.CanEdit(),
// and so on
}
return View(model);
}
Now in your view just check bool values;
#if(model.Privileges.CanEdit)
{
// print the button
}

How to check if user role has read/write access to a specific view

I have a ASP.NET MVC 4 application. I am trying to implement a solution where I check if a user can access a view, if not then display an error. If the user can access a view then I need to check if that user has read access or read and edit access to that view. If the user has read access then just a normal details view is displayed, if read and edit access then the user can see a details view or can edit the data.
Is something like this possible? I have tried looking through a couple of starter kits that I found on Codeplex but I can't find something like I want. How would this be implemented? If possible, if anyone knows of any sample project that I can download then I will appreciate. I like to work through code, I learn more this way.
I want this all to be database-driven.
You should look more into the AuthorizeAttribute and how to use roles. Basically you give your users roles (that may be fetched from the database) and for every view you wish to limit access in your application you add the Authorize attribute together with the roles. By default I think you can only limit to access or no access but you can probably override and write your custom attribute to give you the behavior you are interested in.
Alternatively, you can manage the user privileges in your controllers. Since you know the authenticated users roles and have access to them you can perform the check in the controller and create the view from that (disabled inputs etc.)
Related
ASP.Net MVC: Can the AuthorizeAttribute be overriden?
Granular permissions with certain requirements for an MVC site
As #Marcus said, you should use Attribute. When action starts, you can check user's role, he has access or not:
public class AttributeForTestAttribute : ActionFilterAttribute
{
public int RoleCanAccess { get; set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
//your validation here..
//for example:
if(_currentUser.Role < RoleHasAccess )
{
//user has not access to this action, redirect him to home page.
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "controller", "Home" }, { "action", "Index" }, { "returnUri", filterContext.HttpContext.Request.RawUrl } });
}
else
{
// user has access to this action
}
}
}
And in controller use your Attribute:
[AttributeForTest(RoleHasAccess = 2)]
public ActionResult SaveProduct(Product product)
{
}

Categories