我成功将我的应用程序从MVC4-EF5更新为MVC5-EF6。
然后我将我的数据库从Simplemebership迁移到Identity 2.0。
我可以登录,但User.IsInRole总是返回false。已经创建了所有正确的表AspNetUsers,AspNetRoles,AspNetUserRoles,AspNetLogins和AspNetClaims,所有列的拼写和类型都是正确的,并且它们已经填充了SimpleMembership表中的数据(已被删除)。
我有一个用户“MyUser”,在AspNetUsers表中是Id = 2,在AspNetRoles表中是一个角色“XYZ”,Id = 2,用户2在AspNetUserRoles表中映射到角色2。
以“MyUser”
登录时 var user = _db.Users.SingleOrDefault(u => u.UserName == User.Identity.Name);
用户确实设置为“MyUser”,但
User.IsInRole("XYZ")
返回false。
我添加了一个测试变量,
var testrole = Roles.GetRolesForUser();
,当在调试中检查testrole时,它返回一个空字符串数组{string [0]}。从立即窗口运行User.IsInRole("XYZ")
将返回false。
我已经阅读了我在Identity,Identity 2.0和从SimpleMembership和Identity 1.0迁移的每个文档,我找不到任何我错过的实现要求(除了我在发布的代码中所做的)使身份工作(并且它在某种程度上起作用,因为登录工作)。
我使用了Identity 2.0的可扩展性钩子来为我的主键实现INT。
WebSecConfig.cs :(从Global.asax.cs调用)(为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>();
}
帐户管理员:
[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);
}
家庭控制器:
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 }
...
}
}
迁移脚本:(以SimpleMembershipToIdentityMigration.sql为模型,并针对Identity 2.0和INT主键进行了修改)
/****** 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
我是否遗漏了有关配置Identity 2.0的内容,或者这是Identity 2.0中的错误?
更新1:
删除了对WebSecConfig的Global.asax.cs调用。这已经掩盖了与User.IsInRole.
在Home Controller UserRouting Action中设置var用户的断点
在调试中运行app并以“MyUser”登录。
介入并将用户设置为“MyUser”
进入var testrole并抛出'Object reference not set to an instance of an object.'
重新启动并再次登录为“MyUser”。
介入并将用户设置为“MyUser”
从立即窗口输入User.IsInRole("XYZ")
,它将返回:
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
然后打开一个警告对话框:
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.
我的基本数据库设置正确或我无法登录。这让我相信我的迁移方式存在细微的差异。有没有人知道我绊倒的地方。
更新2: 我重构了代码和迁移脚本,以使用主键的默认nvarchar,并获得与Update 1相同的结果。
更新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>
我需要将<remove name="RoleManager" />
添加到节点,作为MVC4-MVC5迁移的一部分,我现在已经完成了。{/ p>
现在我回到原来的问题了。 User.IsInRole始终返回false。
如果我从立即窗口运行User.IsAuthenticated
则返回
'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?)
我能够使Identity.UserManager.IsInRole工作。
Home Controller :(修订为使用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 }
...
}
}
这表明我的数据库迁移是正确的。
我在应用程序中的控制器,视图,自定义属性,方法和类中有几十个User.IsInRole调用。据我所知,User.IsInRole仍然是MVC5-EF6中的有效方法。 如果它仍然被认为是一种有效的方法,而不是必须对这个遗留应用程序进行重大重构,那么我再次提出我的原始问题“为什么User.IsInRole在SimpleMembership到Identity 2.0迁移后失败了”?
我在Identity 1.0 MVC应用程序中测试了User.IsInRole并且它可以工作。我将应用程序更新为Identity 2.0,它仍然有效。所以我认为可以说Identity2支持User.IsInRole。
答案 0 :(得分:2)
经过进一步调查后,我发现问题是我从未成功登录,因为用户未经过身份验证,导致User.IsInRole
失败。
var user = UserManager.Find(vM.UserName, vM.Password);
当您在调试中检查user
时,“MyUser”已找到,但如果您进一步向下钻取,则会发现UserName
设置为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
在ApplicationUser
我覆盖了UserName。
[StringLength(15)]
public new string UserName { get; set; }
当我删除UserName覆盖时,一切都开始工作(我将UserName保留为nvarchar(15),而不是null)。 UserName
中的ApplicationUser
覆盖是问题所在。如果要更改nvarchar大小,您显然只需要在迁移脚本中执行此操作。
从SimpleMembrship迁移到Identity 2.0可以正常工作。 User.IsInRole也适用于Identity 2.0。