问题
I successfully updated my application from MVC4-EF5 to MVC5-EF6.
I then migrated my database from Simplemebership to Identity 2.0.
I can login but User.IsInRole always returns false. All the proper tables AspNetUsers, AspNetRoles, AspNetUserRoles, AspNetLogins and AspNetClaims have been created, the spelling and type of all columns are correct and they have been populated with the data from the SimpleMembership tables (which have been deleted).
I have a user "MyUser" which is Id = 2 in the AspNetUsers table and a role "XYZ" which is Id = 2 in the AspNetRoles table and User 2 is mapped to Role 2 in the AspNetUserRoles table.
When logged in as "MyUser"
var user = _db.Users.SingleOrDefault(u => u.UserName == User.Identity.Name);
user does get set to "MyUser" but
User.IsInRole("XYZ")
returns false.
I added a test variable,
var testrole = Roles.GetRolesForUser();
, when testrole is examined in debug it returns an empty string array {string[0]}. Running User.IsInRole("XYZ")
from the Immediate Window returns false.
I've read through every document I can find on Identity, Identity 2.0 and migrating from SimpleMembership and Identity 1.0 and I can't find any implementation requirements (beyond what I've done in my posted code) that I have missed to make Identity work (and it is working at some level since then login works).
I have used Identity 2.0's extensibility hook to implement INT for my Primary keys.
WebSecConfig.cs: (called from Global.asax.cs) (removed this code for UPDATE: 1)
using WebMatrix.WebData;
namespace MyApplication
{
public static class WebSecConfig
{
public static void RegisterWebSec()
{
WebSecurity.InitializeDatabaseConnection
("MyApplication", "AspNetUsers", "Id", "UserName", autoCreateTables: true);
}
}
}
ApplicationUser:
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
[StringLength(15)]
public new string UserName { get; set; }
public int AcId { get; set; }
public int LcId { get; set; }
}
public class CustomRole : IdentityRole<int, CustomUserRole>
{
public CustomRole() { }
public CustomRole(string name) { Name = name; }
}
public class CustomUserRole : IdentityUserRole<int> { }
public class CustomUserClaim : IdentityUserClaim<int> { }
public class CustomUserLogin : IdentityUserLogin<int> { }
IdentityDbContext:
public class MyDb : IdentityDbContext<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public MyDb() : base("MyApplication") { }
// public virtual DbSet<UserProfiles> Users { get; set; }
public virtual DbSet<MyTable> MyTables { get; set; } // properties marked virtual for Mocking override
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
Account Controller:
[RequireHttps]
[Authorize]
public class AccountController : Controller
{
private readonly IUserService _userService;
public UserManager<ApplicationUser, int> UserManager { get; private set; }
public AccountController()
: this(new UserService(), new UserManager<ApplicationUser, int>(new UserStore<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>new MyDb()))) { }
public AccountController(IUserService userService, UserManager<ApplicationUser, int> userManager)
{ _userService = userService; UserManager = userManager; }
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login() { return View(); }
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginVm vM)
{
if (ModelState.IsValid)
{
var user = UserManager.Find(vM.UserName, vM.Password);
if (user != null)
{
FormsAuthentication.SetAuthCookie(user.UserName, false);
return RedirectToAction("UserRouting", "Home");
}
}
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(vM);
}
Home Controller:
using System;
using System.Web.Mvc;
using MyApplication.Models;
using System.Linq;
using System.Web.Security;
namespace MyApplication.Controllers
{
[Authorize]
public class HomeController : Controller
{
private readonly MyDb _db = new MyDb();
public ActionResult UserRouting()
{
var user = _db.Users.SingleOrDefault(u => u.UserName == User.Identity.Name);
var testrole = Roles.GetRolesForUser(); // for testing, remove from production
if (User.IsInRole("XYZ")) { // mycode }
...
}
}
Migration Script: (modeled on SimpleMembershipToIdentityMigration.sql and modified for Identity 2.0 and INT Primary Keys)
/****** Object: Table [dbo].[AspNetRoles] Script Date: 4/30/14 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID('dbo.AspNetUserRoles', 'U') IS NOT NULL
DROP TABLE [dbo].[AspNetUserRoles]
GO
--IF OBJECT_ID('dbo.AspNetUserLogins', 'U') IS NOT NULL
-- DROP TABLE [dbo].[AspNetUserLogins]
--GO
IF OBJECT_ID('dbo.AspNetUserClaims', 'U') IS NOT NULL
DROP TABLE [dbo].[AspNetUserClaims]
GO
IF OBJECT_ID('dbo.AspNetRoles', 'U') IS NOT NULL
DROP TABLE [dbo].[AspNetRoles]
GO
IF OBJECT_ID('dbo.AspNetUsers', 'U') IS NOT NULL
DROP TABLE [dbo].[AspNetUsers]
GO
CREATE TABLE [dbo].[AspNetUsers] (
--[Id] NVARCHAR (128) NOT NULL,
[Id] INT NOT NULL,
[UserName] NVARCHAR (15) NULL,
[AcId] INT NOT NULL,
[LcId] INT NOT NULL,
[Email] NVARCHAR (256) NULL,
[EmailConfirmed] BIT DEFAULT ((0)) NULL,
[PasswordHash] NVARCHAR (MAX) NULL,
[SecurityStamp] NVARCHAR (MAX) NULL,
[PhoneNumber] NVARCHAR (MAX) NULL,
[PhoneNumberConfirmed] BIT DEFAULT ((0)) NULL,
[TwoFactorEnabled] BIT DEFAULT ((0)) NULL,
[LockoutEndDateUtc] DATETIME NULL,
[LockoutEnabled] BIT DEFAULT ((0)) NULL,
[AccessFailedCount] INT DEFAULT ((0)) NOT NULL,
[CreateDate] DATETIME NULL,
CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE TABLE [dbo].[AspNetRoles] (
--[Id] NVARCHAR (128) NOT NULL,
[Id] INT NOT NULL,
[Name] NVARCHAR (256) NOT NULL,
CONSTRAINT [PK_dbo.AspNetRoles] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE TABLE [dbo].[AspNetUserRoles] (
-- [UserId] NVARCHAR (128) NOT NULL,
-- [RoleId] NVARCHAR (128) NOT NULL,
[UserId] INT NOT NULL,
[RoleId] INT NOT NULL,
CONSTRAINT [PK_dbo.AspNetUserRoles] PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC),
CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[AspNetRoles] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_RoleId]
ON [dbo].[AspNetUserRoles]([RoleId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_UserId]
ON [dbo].[AspNetUserRoles]([UserId] ASC);
GO
CREATE TABLE [dbo].[AspNetUserLogins] (
--[UserId] NVARCHAR (128) NOT NULL,
[UserId] INT NOT NULL,
[LoginProvider] NVARCHAR (128) NOT NULL,
[ProviderKey] NVARCHAR (128) NOT NULL,
CONSTRAINT [PK_dbo.AspNetUserLogins] PRIMARY KEY CLUSTERED ([UserId] ASC, [LoginProvider] ASC, [ProviderKey] ASC),
CONSTRAINT [FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_UserId]
ON [dbo].[AspNetUserLogins]([UserId] ASC);
GO
CREATE TABLE [dbo].[AspNetUserClaims] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[ClaimType] NVARCHAR (MAX) NULL,
[ClaimValue] NVARCHAR (MAX) NULL,
-- [UserId] NVARCHAR (128) NOT NULL,
[UserId] INT NOT NULL,
CONSTRAINT [PK_dbo.AspNetUserClaims] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.AspNetUserClaims_dbo.AspNetUsers_User_Id] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_User_Id]
ON [dbo].[AspNetUserClaims]([UserId] ASC);
GO
INSERT INTO AspNetUsers(Id, UserName, AcId, LcId, PasswordHash, SecurityStamp, CreateDate )
SELECT UserProfile.UserId, UserProfile.UserName, UserProfile.BaId, UserProfile.OfcId,
webpages_Membership.Password, webpages_Membership.PasswordSalt, CreateDate
FROM UserProfile
LEFT OUTER JOIN webpages_Membership ON UserProfile.UserId = webpages_Membership.UserId
GO
INSERT INTO AspNetRoles(Id, Name)
SELECT RoleId, RoleName
FROM webpages_Roles
GO
INSERT INTO AspNetUserRoles(UserId, RoleId)
SELECT UserId, RoleId
FROM webpages_UsersInRoles
GO
IF OBJECT_ID('dbo.webpages_OAuthMembership', 'U') IS NOT NULL
DROP TABLE [dbo].[webpages_OAuthMembership]
GO
IF OBJECT_ID('dbo.webpages_UsersInRoles', 'U') IS NOT NULL
DROP TABLE [dbo].[webpages_UsersInRoles]
GO
IF OBJECT_ID('dbo.webpages_Roles', 'U') IS NOT NULL
DROP TABLE [dbo].[webpages_Roles]
GO
IF OBJECT_ID('dbo.UserProfile', 'U') IS NOT NULL
DROP TABLE [dbo].[UserProfile]
GO
IF OBJECT_ID('dbo.webpages_Membership', 'U') IS NOT NULL
DROP TABLE [dbo].[webpages_Membership]
GO
IF OBJECT_ID('dbo.__MigrationHistory', 'U') IS NOT NULL
DROP TABLE [dbo].[__MigrationHistory]
GO
Have I missed something on configuring Identity 2.0 or is this a bug in Identity 2.0?
UPDATE 1:
Removed the Global.asax.cs call to WebSecConfig. This had been masking a different issue with User.IsInRole.
Set breakpoint on var user in Home Controller UserRouting Action
Run app in debug and login in as "MyUser".
Step in and user gets set to "MyUser".
Step into var testrole and it throws 'Object reference not set to an instance of an object.'
Re-start and login again as "MyUser".
Step in and user gets set to "MyUser".
From Immediate Window enter User.IsInRole("XYZ")
and it returns:
A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
A first chance exception of type 'System.Web.HttpException' occurred in System.Web.dll
A first chance exception of type 'System.Web.HttpException' occurred in System.Web.dll
A first chance exception of type 'System.Web.HttpException' occurred in System.Web.dll
And opens a Warning dialogue box with:
HttpException was unhandled
An unhandled exception of type 'System.Web.HttpException" occurred in System.Web.dll
Additional information: Unable to connect to SQL Server database.
My basic Database setup is correct or I wouldn't have been able to login. This leads me to believe there is a small discrepancy in how I ran the migration. Does anyone have an idea where I tripped up.
UPDATE 2: I refactored the code and migration script to use the default nvarchar for the Primary Keys and got the same results as Update 1.
UPDATE 3:
Web.Config:
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<sectionGroup name="nwebsec">
<!-- For information on how to configure NWebsec please visit: http://nwebsec.codeplex.com/wikipage?title=Configuration -->
<section name="httpHeaderSecurityModule" type="NWebsec.Modules.Configuration.HttpHeaderSecurityConfigurationSection, NWebsec, Version=3.0.2.0, Culture=neutral, PublicKeyToken=3613da5f958908a1" requirePermission="false" />
</sectionGroup>
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --></configSections>
<connectionStrings>
<add name="MyApplication" connectionString="data source=.\SqlExpress;Integrated Security=SSPI;MultipleActiveResultSets = true;initial catalog=MyDb" providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="elmah.mvc.disableHandler" value="false" />
<add key="elmah.mvc.disableHandleErrorFilter" value="false" />
<add key="elmah.mvc.requiresAuthentication" value="true" />
<add key="elmah.mvc.IgnoreDefaultRoute" value="false" />
<add key="elmah.mvc.allowedRoles" value="Admin,CorpS" />
<!--<add key="elmah.mvc.allowedUsers" value="*" />-->
<add key="elmah.mvc.route" value="elmah" />
</appSettings>
<!--
For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.
The following attributes can be set on the <httpRuntime> tag.
<system.Web>
<httpRuntime targetFramework="4.5.1" />
</system.Web>
-->
<system.web>
<customErrors mode="Off" />
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5" useFullyQualifiedRedirectUrl="true" maxRequestLength="100000" enableVersionHeader="false" />
<!-- value is Kb, need to avoid crash with file upload of large files -->
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="15" />
</authentication>
<pages>
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
</namespaces>
</pages>
<!--<roleManager enabled="true" defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>-->
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
</httpModules>
<sessionState cookieName="My_SessionId" />
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules>
<add name="NWebsecHttpHeaderSecurityModule" type="NWebsec.Modules.HttpHeaderSecurityModule, NWebsec, Version=3.0.2.0, Culture=neutral, PublicKeyToken=3613da5f958908a1" />
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
<remove name="RoleManager" />
</modules>
<httpProtocol>
<customHeaders>
<clear />
</customHeaders>
</httpProtocol>
<security>
<requestFiltering>
<hiddenSegments>
<add segment="NWebsecConfig" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.6.1.0" newVersion="5.6.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.6.1.0" newVersion="5.6.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Spatial" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.6.1.0" newVersion="5.6.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly><assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" /></dependentAssembly>
<dependentAssembly><assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" /></dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly><assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" /><bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" /></dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" />
</dependentAssembly>
</assemblyBinding>
<!-- This prevents the Windows Event Log from frequently logging that HMAC1 is being used (when the other party needs it). -->
<legacyHMACWarning enabled="0" />
<!-- When targeting ASP.NET MVC 3, this assemblyBinding makes MVC 1 and 2 references relink
to MVC 3 so libraries such as DotNetOpenAuth that compile against MVC 1 will work with it.
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
-->
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.net>
<defaultProxy enabled="true" />
<settings>
<!-- This setting causes .NET to check certificate revocation lists (CRL)
before trusting HTTPS certificates. But this setting tends to not
be allowed in shared hosting environments. -->
<!--<servicePointManager checkCertificateRevocationList="true"/>-->
</settings>
</system.net>
<nwebsec>
<httpHeaderSecurityModule xmlns="http://nwebsec.com/HttpHeaderSecurityModuleConfig.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="NWebsecConfig/HttpHeaderSecurityModuleConfig.xsd">
<redirectValidation enabled="true"> <add allowedDestination="https://localhost/" /> </redirectValidation>
<securityHttpHeaders>
<x-Frame-Options policy="Deny" />
<strict-Transport-Security max-age="365" />
<x-Content-Type-Options enabled="true" />
</securityHttpHeaders>
</httpHeaderSecurityModule>
</nwebsec>
<elmah>
<security allowRemoteAccess="false" />
</elmah>
</configuration>
I needed to add <remove name="RoleManager" />
to the node as part of the MVC4-MVC5 migration, which I have now done.
Now I'm back to my original problem. User.IsInRole always returns false.
If I run User.IsAuthenticated
from the Immediate Window it returns
'System.Security.Principal.IPrincipal' does not contain a definition for 'IsAuthenticated' and no extension method 'IsAuthenticated' accepting a first argument of type 'System.Security.Principal.IPrincipal' could be found (are you missing a using directive or an assembly reference?)
I was able to get Identity.UserManager.IsInRole to work.
Home Controller: (revised to use UserManager)
using System;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using MyApplication.Models;
using System.Linq;
//using System.Web.Security;
namespace MyApplication.Controllers
{
[Authorize]
public class HomeController : Controller
{
private readonly MyDb _db = new MyDb();
public UserManager<ApplicationUser> UserManager { get; private set; }
public HomeController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyDb()))) { }
public HomeController(UserManager<ApplicationUser> userManager)
{ UserManager = userManager; }
public ActionResult UserRouting()
{
var user = _db.Users.SingleOrDefault(u => u.UserName == User.Identity.Name);
//var testrole = Roles.GetRolesForUser(); // for testing, remove from production
if (UserManager.IsInRole(user.Id, "XYZ")) { // mycode }
...
}
}
This indicates that my database migration was correct.
I have dozens of calls to User.IsInRole in Controllers, Views, Custom Attributes, methods and classes in my app. To my understanding User.IsInRole is still a valid method in MVC5-EF6. If it is still considered a valid method rather than having to do a major refactoring of this legacy app I pose again my original question "why is User.IsInRole failing after SimpleMembership to Identity 2.0 migration"?
I've tested User.IsInRole in an Identity 1.0 MVC app and it works. I updated the app to Identity 2.0 and it still works. So I think it is safe to say that User.IsInRole is supported with Identity 2.0.
回答1:
After further investigation I found the problem to be that I never successfully logged in and since the User wasn't authenticated it caused the User.IsInRole
to fail.
var user = UserManager.Find(vM.UserName, vM.Password);
When you examine user
in debug "MyUser" has been found but if you drill down further you find UserName
is set to null.
User
--{System.Data.Entity.DynamicProxies.ApplicationUser_...} Identity.Models.ApplicationUser{System.Data.Entity.DynamicProxies.ApplicationUser_...} …
base {System.Data.Entity.DynamicProxies.ApplicationUser_...} Identity.Models.ApplicationUser {System.Data.Entity.DynamicProxies.ApplicationUser_...}
base {System.Data.Entity.DynamicProxies.ApplicationUser_...} Microsoft.AspNet.Identity.EntityFramework.IdentityUser …
base {System.Data.Entity.DynamicProxies.ApplicationUser_...} Microsoft.AspNet.Identity.EntityFramework.IdentityUser<string,Microsoft.AspNet.Identity ...
AccessFailedCount 0 int
Claims Count = 0 System.Collections.Generic.ICollection<Microsoft.AspNet.Identity.EntityFramework.IdentityUserClaim> …
Email null string
EmailConfirmed false bool
Id "2" string
LockoutEnabled false bool
LockoutEndDateUtc null System.DateTime?
Logins Count = 0 System.Collections.Generic.ICollection<Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin> …
PasswordHash "xxxxxx" string
PhoneNumber null string
PhoneNumberConfirmed false bool
Roles Count = 2 System.Collections.Generic.ICollection<Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole> …
SecurityStamp "" string
TwoFactorEnabled false bool
UserName null string
In ApplicationUser
I overrode the UserName.
[StringLength(15)]
public new string UserName { get; set; }
When I removed the UserName override everything started working (I left UserName as a nvarchar(15), not null). The UserName
override in ApplicationUser
was the problem. If you want to change the nvarchar sizes you apparently just need to do that in the migration script.
Migrations from SimpleMembrship to Identity 2.0 works. User.IsInRole also works with Identity 2.0.
来源:https://stackoverflow.com/questions/23434279/user-isinrole-failing-after-migrating-simplemembership-database-to-identity-2