MVC (ASP) Implement different user roles on the same action when inherited - c#

I have multiple controllers in my project that do simple basic jobs like Get(int id), Get(), Insert(T t) and Edit(T t). To avoid code duplication I created a GenericController and then inherited all other controllers from this GenericController. Everything works very fine. But I run into issues when I want to implement different user roles on the same controller action when inherited. For example take a look of the code below:
public class GenericController<T>: Controller{
//other actions
[HttpGet]
public async Task<IEnumrable<T>> Get(){
//necessary action goes here
}
[HttpPost]
public async Task<IActionResult> Insert(T t){
//necessary action with t
}
}
[Authorize]
public class ProductController: GenericController<Product>{
//Get action is authorized to everyone
//Insert action is authorized to Manager only
}
[Authorize]
public class EmployeeController: GenericController<Employee>{
//Get action is authorized to everyone
//Insert action is authorized to Owner only
}
In the above snippet the Insert action, that is inherited from GenericController has different authorizations in both Product and Generic Controller.
I don't want to duplicate the code in the inherited controllers. But correct authorization is needed as well. Does anyone know the appropriate solution? Any help will be much appreciated.

Create authorize filter and find the controller and action like below. And then maintain the role.
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();

Related

Why the authorize attribute is not getting overridden on action?

I have this controller which should be only authorized to role= 1 but there is also an action inside it that needs to be authorized to both roles i.e. 1 and 2 so what I did is that I have authorized the controller to role 1 and then overridden the action to have 2 roles but that doesn't work, it's still only accessible to role 1.
why ?
[Authorize(Roles = "1")]
public class ServicesController : BaseController
{
// GET: Services
[OverrideAuthorization]
[Authorize(Roles="1,2")]
[HttpGet]
public JsonResult GetServices()
{
return Json(ServicesRepository.SelectServices(), JsonRequestBehavior.AllowGet);
}
}
Your code is correct. I guess you need to override another action too because it seems like you are not overriding the action that returns the view at first.
Override that action which gets called when you execute the controller.

Using the same RedirectToAction method in ActionMethods in ASP.NET MVC

I basically want to check if the session is still valid for every GET and POST request in my application, however, I don't really want to keep copying and pasting the same code in to every Action Method, I was thinking of using a Base Controller so I can inherit the usage or a static helper controller class (if this can be done??). Are either of these ways the best (or even correct) approach to take?
Example of code
[HttpGet]
[ValidateInput(false)]
public ActionResult SimpleSearch()
{
// I want to run this code of every ActionResult for a GET AND POST
if (!SessionStaticClass.IsUserLoggedIn())
{
return RedirectToAction("Login, Login");
}
}
Thanks
You can use an action filter:
public class NotLoggedInFilter : FilterAttribute, IResultFilter
{
public void OnResultExecuting(ResultExecutingContext filterContext)
{
if (!SessionStaticClass.IsUserLoggedIn())
{
filterContext.Result = new RedirectToAction("Login, Login");
}
}
}
You can then decorate controllers or actions with the attribute, or even have it run for all actions by adding it to the global filter collection.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new NotLoggedInFilter());
}
However, you might want to have a look at authentication filters as a way of handling user authentication instead of using the SessionStaticClass class. A good overview of filter types in MVC can be found here.

Readonly role c# mvc

I have a customroleprovider.cs
I have a user table that has users and their roles. most users have role as user, there are only 3 admin, now i need to create 3 readonly users. these users can only view the whole website, and cannot edit any part of the website. in my views i have these:
#{
var simpleRoles = (RoleProvider)Roles.Provider;
}
#if (simpleRoles.IsUserInRole(User.Identity.Name, "admin"))
{
}
to restrict some areas only for admin, do i need something like this for readonly users?
Since you have admin and users, you may want to create an "admin" area and a "user" area. What I suggested below is only if you have a few views you want to hide from roles. In the admin area you can add the authorize attribute to a base controller for that area so that only admins can update content. Otherwise, you'll have to have if statements in the views if you wanted to hide the update buttons from different appearing for roles, and that could get messy.
UPDATE:
Below is a link for an overview of areas. Areas are nice because you can create an area called "Admin" and inside that area you will have controllers/views/viewmodels, etc... that are separate from a different area. Inside this area you can include the logic for updating content, whereas if you don't want a role to update content then don't include the logic inside their area. Hopefully the link will do a better job explaining it than I can.
When I use areas for my project, I'll create a base controller that all of my controllers inherit from. An example of what my base controller may look like is:
[Authorize(Roles="Admin")]
public class AdminBaseController : Controller
{
...
}
Then in all of my controllers in the area I'll inherit from the AdminBaseController so that only admins can access this section of the website.
public class HomeController : AdminBaseController
{
...
}
http://www.dotnet-tricks.com/Tutorial/mvc/a9P1010113-MVC-Areas-with-example.html
Adding an Authorize attribute on the view:
For example, if you only want admin's to view the view.cshtml file then you can do something like this on the controller action:
[Authorize(Roles="admin")]
public ActionResult View()
{
....
}
If user's aren't in that role then they will be be able to access that view.
For multiple roles, you can do:
[Authorize(Roles="admin, user")]
public ActionResult View()
{
...
}
This will allow anybody that is an admin OR user to view the page. (They don't have to be in both roles).
Elaborating on my comment above. Decorating your controller actions with the Authorization Attribute will lock down it to the specific role(s). This does not solve the issue of a read-only type role. You will need some logic in the controller action to evaluate the role then return a different view. I recommend placing this in a BaseController. Have your other controllers inherit it:
public abstract class BaseController : Controller
{
public bool IsReadOnly { get; set; }
public BaseController()
{
this.IsReadOnly = Roles.IsUserInRole("readonly");
}
}
public class HomeController : BaseController
{
[Authorize(Roles = "admin, user, readonly")]
public ActionResult Edit(int id)
{
if (!IsReadOnly)
{
return View("Details");
}
... other stuff
}
}
Try This in .cshtml
#if ( User.Identity.IsAuthenticated ){
if ( User.IsInRole("Admin") ){
#Html.ActionLink("Admin", "AdminController")
}
}

Role Management in MVC3

I want to add a functionality to application such that only admin can create users and he can provide access to particular pages to user.
He can create roles and can provide users different roles.
I am using Visual Studio 2010 and building this application in MVC3.
Please give me suggestions to make over it.
Thanks in advance.
1.Decorate your user creation and permission setting actions with Authorize attribute
(Notify, that usage of Roles property of AuthorizeAttribute requires implementation of MembershipProvider (standart or custom) and registering it in web.config)
public class AccountController : Controller
{
[HttpGet, Authorize(Roles = "Admin")]
public ViewResult CreateUser()
{
return View();
}
[HttpPost, Authorize(Roles = "Admin")]
public ActionResult CreateUser()
{
//... call service method to create user
}
[HttpPost, Authorize(Roles = "Admin")]
public ActionResult AssignPageToUser(int userId, string controllerName, string ActionName)
{
//... insert record into table (UserPermissions) with attributes (userId, actionName, controllerName)
}
// other methods without decoration by authorize attribute
}
Next paragraphs are correct if you really want to have full control on action permissions separately for each user.
If you think, that your permissions can group in finite and small number on roles - you can decorate all actions/controllers by authorize attribute and specify roles, for which action/controller available: [Authorize("Customer, Manager, RegionalAdmin")] and give admin possibility to assign roles to users. But remember, that in is enough to be in only 1 of listed roles to get access, you can't require by this attribute, for example and Admin, and Manager roles.
If you want to require necessarily more than 1 role, use multiple attributes:
public class MyController:Controller
{
[Authorize(Roles = "Manager")]
[Authorize(Roles = "Admin")]
public ActionResult Action1()
{
//...
}
}
2.For your pages you can create your own filter attribute, inherited from authorize attribute, that will check, if action is available for user (i think you want to assign actions but not views to user).
public UserPermissionRequiredAttribute: AuthorizeAttribute
{
public OnAuthorization(AuthorizationContext filterContext)
{
var isAuthenticated = filterContext.HttpContext.User.Identity.IsAuthenticated;
var userName = filterContext.HttpContext.User.Identity.Name;
var actionName = filterContext.ActionDescriptior.ActionName;
var controllerName = filterContext.ActionDescriptior.ControllerDescriptor.ControllerName;
if (isAuthenticated && myUserActionPermissionsService.UserCanAccessAction(userName, actionName, contollerName)
{
filterContext.Result = HttpUnauthorizedResult(); // aborts action executing
}
}
}
3.Decorate actions (controllers), that accessible for users granted by admin:
MySpecialController: Controller
{
[UserPermissionRequired]
Action1()
{
//...
}
[UserPermissionRequired]
Action2()
{
//...
}
Action3()
{
//...
}
}
I don't recommend to use base controller for that aim, because attribute usage is more flexible (you have control on action/controller level instead of only controller level), it is better way to implement separated responsibility. Base controller and filter attribute usage correlated as polymorphism and switch operator.
You're asking a very broad question, and it would take some time to review all your requirements. In any case, you could start by adding a user property to a controller from which all other controllers inherit. Then, you could interrogate that user instance to determine whether they have access to the current route. This solution should give you the foundation you need to add some administrative views for your business requirements.
public class MegaController
{
protected User CurrentUser { get; set; }
protected override void Initialize(RequestContext context)
{
if (requestContext.HttpContext.User.Identity.IsAuthenticated)
{
var userRepository = new UserRepository();
CurrentUser = userRepository.GetUser(
requestContext.HttpContext.User.Identity.Name);
}
}
}
The User and UserRepository types can be your own design. You could use LINQ To Entities to wrap a table named "User" and then within your controllers, you could have access to any fields in that table.
Then, subclass all controllers from MegaController
public class AdminController : MegaController
{
public ActionResult Action1()
{
return View();
}
}
public class SomeOtherController : MegaController
{
public ActionResult Action1()
{
return View();
}
}
Now, this doesn't completely solve your "admin" issue. To do so, you could include logic in MegaController.Initialize() to interrogate the request information. Once you have the requested route and user in context, your code could make a decision whether to allow the request, redirect it, etc.
protected override void Initialize(RequestContext context)
{
// ...
if(context.HttpContext != null)
{
if(context.HttpContext.Request.Path == "some/restricted/route"
&& CurrentUser.Role != "Admin")
{
// or similar error page
var url = Url.Action("UnAuthorized", "Error");
context.HttpContext.Response.Redirect(url);
}
}
}
One caveat with this method is that any new controllers added to your application would have to inherit from MegaController, an architecture that could be easily missed by future developers on the project.
Read about plain old forms authentication to add support for roles and user management.
Then use the [Authorize(Roles="RoleName1")] on controllers or actions to control access.
Check MvcMembership, also available on Nuget. You will have all the basics for User Management in an ASP.NET MVC 3 site.
You will need a user / role provider. Read this tutorial to learn how to setup a database that will hold your users and roles. Once it is setup, you will have all the stored procedures needed for first setup / manual testing created.

Protect entire website behind a login i.e. "Authorize" all Actions within all controllers

title pretty much says it all.
I have a website which will only run behind a login so I want to ensure that nothing can be accessed unless you're logged in. This includes ActionResults, JsonResults etc...
Currently, I have [Authorize] all over my controllers which is quite tedious and not very DRY :)
So can I protect the entire website with 1 magic line of code? (The login page will obviously need to be accessible)
Also, please note that I will still need to further protect some of the Actions to only be used by certain Users/Roles
If you have multiple controllers, then make a AuthorizeController from which you inherit your controllers that must be protected. Just set the [Authorize] attribute to the AuthorizeController:
[Authorize]
public class AuthorizeController: Controller
{
}
public class HomeController : AuthorizeController
{
...
}
// don't inherit AccountController from AuthorizeController
public class AccountController : Controller
{
public ActionResult Login()
{
...
}
}
If you are trying to secure an entire website, you could use a global filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizeAttribute());
}
}
See here for more information http://visualstudiomagazine.com/blogs/tool-tracker/2013/06/authenticating-users-in-aspnet-mvc-4.aspx
Nevermind! I think I found it!
Placing [Authorize] above the Controller class seems to protect all actions, and is further customisable on a per-action basis. YES!
[Authorize]
public class SomeController : Controller
{
// All logged in users
public ActionResult Index()
{
...
}
[Authorize(Roles="Admin")] // Only Admins
public ActionResult Details()
{
...
}
}

Categories

Resources