It’s a step by step tutorial to implement custom role provider and authorization in ASP.NET MVC 4.0 with EF 4.x DB First approach.
Step 1: Create new ASP.NET MVC 4 Web Application > Template: Internet Application, View Engine: Razor.
Add Models:
Step 2: Right Click on Models folder > Add > New Item > Select “ADO.NET Entity Data Model” > Enter Name “SampleModel.edmx” > Add
Select “Generate From Database” > Next
Select Database Connection (New Connection if doesn’t exist), Make sure “Save entity connection setting in web.config as” option true and Enter Name “SampleDBEntities” > Next
Select Your tables and stored proc which is related to role functionality, Enter ModelNamespace “SampleDBModel” > Finish.
Let us consider following table structure:
Custom RoleProvider:
Step 3: Right Click on Project in Solution Explorer > Add New Item > Class > Enter Name: MyRoleProvider.cs
Step 4: Import following namespace and Inherit this class to RoleProvider.
using System.Web.Security;
using <your project namespace>.Models;
Step 5: Click on RoleProvider > Select “Implement abstract class” option. It’ll generate methods of RoleProvider.
Read Also: Custom role provider based sitemap navigation in asp.net
Step 6: implement GetRolesForUser method, It takes username and returns all roles related to user.
public override string[] GetRolesForUser(string username) { using (SampleDBEntities objContext = new SampleDBEntities()) { var objUser = objContext.Users.FirstOrDefault(x => x.AppUserName == username); if (objUser == null) { return null; } else { string[] ret = objUser.Roles.Select(x => x.RoleName).ToArray(); return ret; } } }
You can implement above method as per your database structure. Build the Project.
Step 7: In web.config update RoleManager Tag and define MyRoleProvider class.
<roleManager defaultProvider="CustomRoleProvider" enabled="true" cacheRolesInCookie="false"> <providers> <clear /> <add name="CustomRoleProvider" type="MVC4Role.MyRoleProvider" /> </providers> </roleManager>
Customize Login:
Step 8: Now in AccountController > Login HttpPost action, We’ll validate user as per our database structure.
[AllowAnonymous] [HttpPost] public ActionResult Login(LoginModel model, string returnUrl) { if (ModelState.IsValid) { using (SampleDBEntities objContext = new SampleDBEntities()) { var objUser = objContext.Users.FirstOrDefault(x => x.AppUserName == model.UserName && x.Password == model.Password); if (objUser == null) { ModelState.AddModelError("LogOnError", "The user name or password provided is incorrect."); } else { FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) { return Redirect(returnUrl); } else { //Redirect to default page return RedirectToAction("RedirectToDefault"); } } } } // If we got this far, something failed, redisplay form return View(model); }
In above method, we are validating username and password and redirect on successful login. You can create custom membership provider, implement ValidateUser method and use it here to check validation.
Role Based Redirection:
Step 9: You might want role based redirection on successful login. To implement this, let us create one more action say RedirectToDefault.
public ActionResult RedirectToDefault() { String[] roles = Roles.GetRolesForUser(); if (roles.Contains("Administrator")) { return RedirectToAction("Index","Admin"); } else if (roles.Contains("Dealer")) { return RedirectToAction("Index", "Dealer"); } else if (roles.Contains("PublicUser")) { return RedirectToAction("Index", "PublicUser"); } else { return RedirectToAction("Index"); } }
Why New Action?
Now one question arises, why to create separate action for this? We can put direct if else in same login action. If we do this then GetRolesForUser or User.IsInRole will not work. FormsAuthentication requires one redirection to set cookies…etc. That’s why we redirects to another action and redirect again to action as per user role.
For testing, Create two new empty controllers say Admin and Dealer and create views of default actions.
Admin View:
@{ ViewBag.Title = "Index"; } <h2>Welcome</h2> This is Admin Area !!!
Dealer View:
@{ ViewBag.Title = "Index"; } <h2>Welcome</h2> This is dealer section !!!
Note: In ASP.NET MVC 4, default template login is based on ajax. So for testing, open <base url>/Account/login. Similarly, you can update JsonLogin action.
Authorization:
Step 10: You can use Authorize attribute to restrict access by callers to an action method. You can put Authorize attribute on any action or whole controller. Suppose you want to give Admin controller access to admin role only then use
[Authorize(Roles=”Administrator”)]
No other user can access this controller actions.
You can assign multiple roles also. suppose you want to give Dealer controller access to dealer and administrators. then
[Authorize(Roles = "Dealer,Administrator")] public class DealerController : Controller { ... }
If dealer tries to access admin controller It will be redirected to login page.
Hope, It helps.
Hi ,
I using mvc 5,
My custom role provider name :MyRoleProvider
web.config:
the below event does’t fired
public override string[] GetRolesForUser(string username)
{
throw new NotImplementedException();
SqlConnection conOEM = new SqlConnection(ConfigurationManager.ConnectionStrings[“conOEM”].ToString());
conOEM.Open();
// throw new NotImplementedException();
SqlCommand cmd = new SqlCommand(“select * from OEMUserAccess”, conOEM);
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
da.Fill(ds);
string result1 = “”;
string[] array = new string[0];
if (ds.Tables[0].Rows.Count != 0)
{
int a = ds.Tables[0].Rows.Count;
array = new string[a];
for (int i = 0; i < a; i++)
{
array[i] = ds.Tables[0].Rows[i]["Role"].ToString();
}
result1 = ConvertStringArrayToString(array);
}
return array;
}
Please help me provide
Thank You SO much. It helped me a lot. I couldn’t get to redirect after login because i was redirecting right after login and not after one redirection.
But i still have one problem and that is:
I can’t get the UserId. I am using User.Identity.GetUserId(), but it is always null.
Can somebody help me?
Thank you so much! This has just saved me so much hassle and time! :)
What is LoginModel class and how to implement it?
Brij, i have implemented your solution which is correct, thank you for the sharing, but i have a problem with my project.I have implemented customauthorization for many logins forms and in each login page, after submission, i have implemented your solution with authorize attribute for many roles that i have for each login page.The first time, all was correct and i can be able to be redirected to needed page and also logout.After some time, i have debug the project and try to be able to logout, but can not because request.isauthenticated always return false, i don’t know why and can not be able to have another solution. I am thinking that maybe this cookie is always in the browser and i can not be able to set another cookie but i am not sure.any help would be appreciated
Thanks for the post, it real help me.
Why when we remove the roles authorize does not work automatically, because I need to log out and then a login for work? The problem is that the roles are stored in the cookie. I have to find some solution to update the cookie. When do I remove a roles directly in the database the cookie is outdated. I think I have update the cookie to each User request. The example I’m using is on github https://github.com/aspnet/Musi…
Thanks a lot it was very helpful…
I think you need to change this part of code string[] ret = objUser.Roles.Select(x => x.RoleName).ToArray();
return ret;
for this string[] ret = objContext.Roles.Select(x => x.NombreRol).ToArray();
return ret;
This is because to make the change I use the select Control
the problem is with “objUser”
That’s true, He has an error there, I did as you say and it’s worked
I get an error “This method cannot be called during the application’s pre-start initialzation phase. Where should is be placed?
Hi,
How to implement dynamic authorization.
I have a dropdown which contians different types of roles and i have a checkboxlist which contains all the controllers , so that i can select few controllers and assign to the selected role to access.
I wants to use Customized Action Filters which authenticate users when there going to secure pages of the website using AuthorizeCore() or OnAuthorization() which one has to use and how can i use this tel me pls !!!!!
Hi, thanks for the article..the instruction “return RedirectToAction(“RedirectToDefault”);” direct me to the folder (example Admin),
I have to authenticated once again to show the (index,Admin) view….
any answer please??
sorry for my bad english :)
I got “This method cannot be called during the application’s pre-start initialization phase.” error after adding custom provider into my config file. I found this easy fix. http://blog.webactivedirectory.com/2012/11/27/correct-the-custom-membership-provider-error-in-visual-studio-2012-and-asp-net-4-5/ Hope it helps someone. :)
I need to exactly do this but using the Web API template what shall I add to these steps
Hi Brij, any way to pass more parameters to a RoleProvider?
The RoleProvider get the user roles just using the username, and I need to use the username and TenantId to verify roles.
Any idea on how to accomplish this?
I could search the database myself, but MVC will try to use the RoleProvider.
Hi Brij, i have a question about custom Role in asp.net mvc 3. How to implement AddUsersToRoles methods in RoleProvider class with your database schema above? As far as i know, linq to sql can’t support many-to-many relationship. So, How to insert new record in UserInRoles tables? Thanks
Hi,
I have a question for you regarding this custom membership provider.
Can I create it to a class library?
And how do you reference it to web config?
Thank you.
In which web.config I need to change? Web.config of View Folder or main web.config of site ? In Which node? Please give more details.
Do you have the source code for this project please?
MVC4Role is namespace and MyRoleProvider is our custom roleprovider class. It is used to define roleprovider for the app
I could not understand ‘type=”MVC4Role.MyRoleProvider’. help me. Thank you.
MVC4Role is the namespace
Thanks for the article!
You can download the project to provide.
Can I create my database with code first approach instead of the ADO entity data model? If yes, I have trouble with assigning foreign keys, could you perhaps show me the code for the properties?