3

I use ASP.NET Identity 2.0 and I want to figure out if the user that is logged in is of the role "admin". In my seed method I create 3 different roles like this:

var store = new UserStore<ApplicationUser>(context);
               var userManager = new ApplicationUserManager(store);
               var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));

               string roleName = "admin";
               if (!roleManager.RoleExists(roleName))
               {
                   roleManager.Create(new IdentityRole(roleName));
               }
               roleName = "superuser";
               if (!roleManager.RoleExists(roleName))
               {
                   roleManager.Create(new IdentityRole(roleName));
               }
               roleName = "user";
               if (!roleManager.RoleExists(roleName))
               {
                   roleManager.Create(new IdentityRole(roleName));
               }


               var user = new ApplicationUser() { Email = "nsg@gmail.com", UserName = "Niclas" };
               userManager.Create(user, "123456");
               userManager.AddToRole(user.Id, "Admin");

Depended on whether the user is admin or not he needs to see different links in the nav-bar, So I have made this code:

        <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("Lenio", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    @if (Roles.IsUserInRole(User.Identity.Name,"admin"))
                    {
                        <li>@Html.ActionLink("Admins", "Index", "Admins")</li>
                        <li>@Html.ActionLink("SuperUsers", "Index", "SuperUsers")</li>
                        <li>@Html.ActionLink("Users", "Index", "Users")</li>
                        <li>@Html.ActionLink("Areas", "Index", "Areas")</li>
                        <li>@Html.ActionLink("CDs", "Index", "CommunicationDevices")</li>
                        <li>@Html.ActionLink("Houses", "Index", "Houses")</li>
                        <li>@Html.ActionLink("Lendings", "Index", "Lendings")</li>
                        <li>@Html.ActionLink("Logs", "Index", "Logs")</li>
                        <li>@Html.ActionLink("Sensors", "Index", "Sensors")</li>
                    }
                    @if (User.IsInRole("user"))
                    {
                        <li>@Html.ActionLink("User", "Index", "Din bruger")</li>
                    }
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                </ul>
                @Html.Partial("_LoginPartial")
            </div>
        </div>
    </div>

The problem is that when the code reach the @if (Roles.IsUserInRole(User.Identity.Name,"admin")) part i get an {"Invalid object name 'dbo.aspnet_SchemaVersions'."} exception. I don't have a aspnet_SchemaVersions table in my db and I don't want it. Here is a picture of the tables that are related to Identity I have: Identity Tables

The db is hosted on azure.

UPDATE

DavidG posted an answer that fixes the inital problem but it dosen't fix that I can't use:

[Authorize(Roles = "admin")]

I need to be able to use this attribute but I cant as I get this exception:

> [SqlException (0x80131904): Invalid object name 'dbo.aspnet_SchemaVersions'.]
   System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +1789294
   System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +5340642
   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +244
   System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +1691
   System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +275
   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds) +1421
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) +177
   System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) +208
   System.Data.SqlClient.SqlCommand.ExecuteNonQuery() +163
   System.Web.Util.SecUtility.CheckSchemaVersion(ProviderBase provider, SqlConnection connection, String[] features, String version, Int32& schemaVersionCheck) +392
   System.Web.Security.SqlRoleProvider.CheckSchemaVersion(SqlConnection connection) +64
   System.Web.Security.SqlRoleProvider.GetRolesForUser(String username) +753
   System.Web.Security.RolePrincipal.IsInRole(String role) +9625099
   System.Linq.Enumerable.Any(IEnumerable`1 source, Func`2 predicate) +146
   System.Web.Mvc.AuthorizeAttribute.AuthorizeCore(HttpContextBase httpContext) +333
   System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext) +379
   System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) +143
   System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__19(AsyncCallback asyncCallback, Object asyncState) +1680
   System.Web.Mvc.Async.WrappedAsyncResult`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +59
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
   System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag, Int32 timeout) +94
   System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +559
   System.Web.Mvc.Controller.<BeginExecuteCore>b__1c(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState) +82
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +73
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
   System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +105
   System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +588
   System.Web.Mvc.Controller.<BeginExecute>b__14(AsyncCallback asyncCallback, Object callbackState, Controller controller) +47
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +65
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
   System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +139
   System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +484
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +50
   System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState) +98
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +73
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
   System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +106
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +446
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +88
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +50
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
Niclas Gleesborg
  • 566
  • 1
  • 5
  • 23

2 Answers2

4

The reason for this error is that your application is trying to first connect using the old version of Identity. You shouldn't use the 'legacy' versions of the objects to manage roles. Use the new UserManager and RoleManager classes.

For example:

var store = new UserStore<ApplicationUser>(context);
var userManager = new ApplicationUserManager(store);    

if(userManager.IsInRole(userId, "NameOfRole")
{
    //do stuff
}

To use this in your views, you can create your own helpers:

namespace MyProject.MyNamespace.MyExtensions
{
    public static class IdentityExtensions
    {
        public static bool IsInIdentityRole(this IPrincipal user, string role)
        {
            var userManager = GetUserManager(); //implement this!
            return userManager.IsInRole(user.Identity.GetUserId(), role); 
        }
    }
}

Make sure your views know about this namespace, add this line into the web.config file in your Views folder (NOT the main web.config!):

<add namespace="MyProject.MyNamespace.MyExtensions"/>

And use in your view like this:

@if (User.IsInIdentityRole("admin"))
{
    <li>@Html.ActionLink("Admins", "Index", "Admins")</li>
}
DavidG
  • 113,891
  • 12
  • 217
  • 223
  • The view I'm using it in is the _Layout.cshtml where should I put the helper methods to be able to access them in that view? What should `GetUserManager()` do besides `return new ApplicationUserManager(store)` ? – Niclas Gleesborg Oct 29 '14 at 09:45
  • Updated the answer to include that. – DavidG Oct 29 '14 at 09:49
  • The GetManager() method I implemented like your first example and with the other things you said it all worked. – Niclas Gleesborg Oct 29 '14 at 10:03
  • -1 I'm sorry, but you don't need to create a hack with static extension where you create `UserManager` object. `IPrinciple` implements method `IsInRole()` and that works perfectly well with Identity. And in Razor views you get `User` of type `IPrincipal` and if you call `@User.IsInRole("admin")` - it will tell you if user is in role of Admin. No need to go to the database. – trailmax Oct 29 '14 at 10:28
  • @DabidG I found out that I get the same problem when using `[Authorize(Roles = "admin")]` and I need to be able to do that. – Niclas Gleesborg Oct 29 '14 at 11:29
  • 2
    @Niclassg In your `web.config`, inside `` make sure this line exists: `` – DavidG Oct 29 '14 at 11:35
  • `Roles.IsInRole` is part of MembershipProvider. It should not be used (and should not work) with Identity framework. – trailmax Oct 29 '14 at 12:08
  • Sorry I meant User.IsInRole – Niclas Gleesborg Oct 29 '14 at 13:14
  • @H.deJonge Thanks for the edit suggestion, but your change would introduce some very dangerous code - never use `Task.Wait()` – DavidG Dec 04 '19 at 16:36
0

Instead of calling

@if (Roles.IsUserInRole(User.Identity.Name,"admin"))

which calls to old MembershipProvider use this call:

@if (User.IsInRole("admin"))

This uses capability of new Identity framework. No need to implement anything. Also this does not call to database to check for roles - it uses cookie information which stores user roles.

Update

If you get exception about System.Web.Security.RolePrincipal that means your membership provider is not completely turned off and you see it fighting it's last chance.

Make sure that in your web.config you have:

<system.WebServer>
     <modules>
       <remove name="FormsAuthentication" />

and in

<appSettings>
    <add key="enableSimpleMembership" value="false" />

Make sure your cookies are deleted and you can login again. After that when you inspect @User in Razor view in debugger, you should see ClaimsPrincipal object, not RolePrincipal. And ClaimsPrincipal should be used throughout the system when user is logged in - that's what Identity uses. If you don't get IdentityPrincipal, means your sign-in process does not work correctly.

trailmax
  • 34,305
  • 22
  • 140
  • 234