将SimpleMembership数据库迁移到Identity 2后,User.IsInRole失败

时间:2014-05-02 18:02:52

标签: asp.net-identity entity-framework-6.1

我成功将我的应用程序从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。

1 个答案:

答案 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。