我在这里使用了一种新方法来得出答案。我得出答案的方式比答案本身更重要。
寻找答案的方法
- 查找 .Net Framework 源代码。在这种情况下,它是
Microsoft.AspNet.Identity.Core 和 Microsoft.AspNet.Identity.Owin
- 找到我想与之交互操作的“黑匣子”类。在这种情况下,它是
UserManager 和 SignInManager
- 找到我想要交互操作的入口“黑盒”方法。在这种情况下,它是
SignInManager.PasswordSignInAsync(),在 AccountController.Login(LoginViewModel model, string returnUrl) 中调用
- 从源代码中复制方法并将其粘贴到样板子类中。在这种情况下,它是
ApplicationSignInManager。通过将 virtual 关键字更改为 override 将方法转换为覆盖。
- 找到并注释掉任何与我的后端 dll 不兼容或无法正常工作或不适用于我的应用程序的代码。不要过度评论或假设任何事情。谨慎评论。
- 如果需要可以由我的后端 dll 提供的功能,请使用我的后端 dll 提供。
- 如果这个“黑盒方法”(我们刚刚制作了白盒)调用了更多的暗方法,请对该方法也重复第 4 步到第 6 步,以此类推,以递归方式进行。您可以在有或没有调试的情况下执行此操作。我使用调试是因为这比相信我的眼睛跟随代码流更容易。
使用这种方法的结果
ApplicationSignInManager.cs(覆盖 2 个方法,注释掉会中断的代码)
using System.Threading.Tasks;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using AACOMvc.Models;
using System.Data.Entity.Utilities;
using Microsoft.AspNet.Identity;
using System;
namespace AAAMvc
{
// Configure the application sign-in manager which is used in this application.
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override async Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
{
if (UserManager == null)
{
return SignInStatus.Failure;
}
var user = await UserManager.FindByNameAsync(userName).WithCurrentCulture();
if (user == null)
{
return SignInStatus.Failure;
}
//if (await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
//{
// return SignInStatus.LockedOut;
//}
if (await UserManager.CheckPasswordAsync(user, password).WithCurrentCulture())
{
//await UserManager.ResetAccessFailedCountAsync(user.Id).WithCurrentCulture();
return await SignInOrTwoFactor(user, isPersistent).WithCurrentCulture();
}
//if (shouldLockout)
//{
// // If lockout is requested, increment access failed count which might lock out the user
// await UserManager.AccessFailedAsync(user.Id).WithCurrentCulture();
// if (await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
// {
// return SignInStatus.LockedOut;
// }
//}
return SignInStatus.Failure;
}
private async Task<SignInStatus> SignInOrTwoFactor(ApplicationUser user, bool isPersistent)
{
var id = Convert.ToString(user.Id);
//if (await UserManager.GetTwoFactorEnabledAsync(user.Id).WithCurrentCulture()
// && (await UserManager.GetValidTwoFactorProvidersAsync(user.Id).WithCurrentCulture()).Count > 0
// && !await AuthenticationManager.TwoFactorBrowserRememberedAsync(id).WithCurrentCulture())
//{
// var identity = new ClaimsIdentity(DefaultAuthenticationTypes.TwoFactorCookie);
// identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, id));
// AuthenticationManager.SignIn(identity);
// return SignInStatus.RequiresVerification;
//}
await SignInAsync(user, isPersistent, false).WithCurrentCulture();
return SignInStatus.Success;
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
}
}
}
ApplicationUserManager.cs(覆盖 4 个方法,注释会破坏的代码,并添加我的代码以使其以旧版 dll 的方式工作)
using System;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using AACOMvc.Models;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using HerculesBusinessModel;
using System.Security.Claims;
using System.Data.Entity.Utilities;
namespace AAAMvc
{
// Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static UserCredentialsType UserCredentials
{
get
{
return (UserCredentialsType)System.Web.HttpContext.Current.Session["UserProfile"];
}
set
{
System.Web.HttpContext.Current.Session["UserProfile"] = value;
}
}
public override async Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
if (user == null)
{
return false;
}
await Task.Delay(0);
string SoftwareLicenses = "blahblahblah";
try
{
UserCredentials = UserProfileType.Login(user.UserName, password, 0, SoftwareLicenses);
return true;
}
catch (HerculesBusinessRuleException ex)
{
}
return false;
}
public override async Task<ClaimsIdentity> CreateIdentityAsync(ApplicationUser user, string authenticationType)
{
//ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException("user");
}
const string IdentityProviderClaimType =
"http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider";
const string DefaultIdentityProviderClaimValue = "ASP.NET Identity";
var id = new ClaimsIdentity(authenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id, ClaimValueTypes.String));
id.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, user.UserName, ClaimValueTypes.String));
id.AddClaim(new Claim(IdentityProviderClaimType, DefaultIdentityProviderClaimValue, ClaimValueTypes.String));
if (SupportsUserRole)
{
IList<string> roles = await GetRolesAsync(user.Id).WithCurrentCulture();
foreach (string roleName in roles)
{
id.AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, roleName, ClaimValueTypes.String));
}
}
if (SupportsUserClaim)
{
//id.AddClaims(await GetClaimsAsync(user.Id).WithCurrentCulture());
}
return id;
}
ApplicationUser user;
public override async Task<ApplicationUser> FindByNameAsync(string userName)
{
await Task.Delay(0);
var profile = UserProfileType.FetchUserProfileForLogin(userName);
if (profile != null)
{
user = new ApplicationUser()
{
UserName = profile.LoginName,
Id = profile.Id.ToString()
};
foreach (decimal groupId in profile.UserGroups)
{
user.Roles.Add(new IdentityUserRole() { UserId = profile.Id.ToString(), RoleId = groupId.ToString() });
}
}
return user;
}
public override async Task<IList<string>> GetRolesAsync(string userId)
{
////ThrowIfDisposed();
//var userRoleStore = GetUserRoleStore();
//var user = await FindByIdAsync(userId).WithCurrentCulture();
//if (user == null)
//{
// throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.UserIdNotFound,
// userId));
//}
//return await userRoleStore.GetRolesAsync(user).WithCurrentCulture();
await Task.Delay(0);
return user.Roles.Select(r => r.RoleId).ToList();
}
}
}
结论
我很惊讶也很高兴,一个有点机器人的过程可以产生答案。但我更高兴的是,使用这个过程教会了我更多关于一个奇怪的新命名空间 (Microsoft.AspNet.Identity) 的知识,而不是我在数小时的阅读或谷歌搜索中学到的知识。它可能并不完美,但我可以使用相同的过程来改进我所拥有的。