Reputation: 33
I am developing an internal MVC Application using Windows Authentication (WA). Authenticating users using WA is straight forward, however; with respect to user Roles, I have the following requirements:
We will use custom Roles ignoring the AD Roles. For example, a user may have a 'Manager' role in the AD but his app role is set to 'Supervisor'. After the User is authenticated, the system will fetch the user roles and set the CurrentPrincipal accordingly.
For the above, I plan to have 3 tables including User, Role and UserRole. The Role table has the custom roles while the User table consists of company users. The UserRole table will define the mapping between User and their Role(s). The issue I see with this approach is to pre-populate all 3 tables. The User table must have the list of all company employees and is maintained for new/inactive employees. The UserRole table should be set with each user and his role(s) before he logs in.
In the application, User are assigned to different tasks (for example John is supervising Vehicles) plus we need to maintain user activity logs. Assuming the above two points are valid, is it OK to use the ID field in the User table for this purpose?
There is also a chance that later, we may deploy the application over the public domain. In such a case, how can we use the existing User/Role infrastructure for this purpose.
Thanks in advance.
Upvotes: 2
Views: 1218
Reputation: 1965
You are in exactly the same boat as me, my friend! I managed to do this through a Custom Authorization Attribute. Here are a couple of points that I have stumbled on through this process.
I did not create my own user table. You can, but you can query AD for users depending on the amount of users on your domain and link it to your Roles / Activities tables using the Guid to search. If you do create a users table that mirrors AD, use the Guid for the user. This way, if the login/name/anything else changes, the Guid stays the same.
Custom authorization attribute:
namespace YourSite.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public class AuthRoleAttribute : ActionFilterAttribute
{
public string RoleName { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!ViewIsAuthorizedActivity(RoleName)) // create a bool function to see if your user is in this role... check your db or whatever
{
string requestMethod = filterContext.HttpContext.Request.HttpMethod;
if (requestMethod == "GET")// I chose two different means of forbidding a user... this just hides the part of the page based on the @if(ViewBag.Authorization = "FORBIDDEN") where you render a partial, else show the view
{
filterContext.Controller.ViewBag.Authorization = "FORBIDDEN";
}
else if (requestMethod == "POST") // This prevents over posting by redirecting them completely away from that controller... also prevents them from posting if they have the page loaded and you remove permission
{ // Hiding a part of the page doesn't matter for the POST if the page is already loaded
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "controller", "Home" },
{ "action", "Forbidden" },
{ "area", ""}
});
}
base.OnActionExecuting(filterContext);
}
}
}
}
How GETs are handled in the view:
@if (ViewBag.Authorization == "FORBIDDEN")
{
ViewBag.Title = "Forbidden!";
@Html.Partial("~/Views/Forbidden.cshtml");
}
else
<!-- User is not forbidden and have the view here -->
Note that for the POSTs the user is redirected away from the controller to the Forbidden controller.
Attribute on controller:
[AuthRole(RoleName = "Admin")]
public ActionResult YourController()
I also made a extension to the User so things may be hidden in the view if they don't have permission:
public static bool IsAuthorized(this IPrincipal user, string roleName)
{
return Attributes.AuthActivityAttribute.ViewIsAuthorizedByRole(roleName); // function determining if the user is in that role, therefore show what you want to show in the view or don't show it if false
}
Which is called by:
@if (User.IsAuthorized("Admin"))
{
<!-- show something, a link, etc. -->
}
Hopefully this gives you a better head start than I had. Let me know if you have questions.
Upvotes: 0