如何使MVC5 AccountController与旧版安全dll进行通信

时间:2016-10-20 17:14:31

标签: authentication asp.net-mvc-5

我继承了一个遗留框架dll,它有自己的方法来登录和查看用户所属的“组”。这是一个非常典型的本土安全模块。你通过传统的dll方法与它交谈。它不使用或与任何现代.Net认证/授权框架交谈。

我创建了一个MVC5应用程序并获得了很多样板文件,包括AccountController,我完全认为最好全部使用它,因为那是“用谷物编码”而不是“反对谷物”。

我想对MVC项目样板代码进行 minimal 更改,让它从遗留dll中获取答案。一旦有了这些认证/授权答案,我希望它继续进行,好像它从.Net框架获得了那些答案。

仅使用登录方案作为示例,

以下是AccountController中的给定样板方法:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
  if (!ModelState.IsValid)
  {
    return View(model);
  }

  //SignInStatus result = Login(model.Email, model.Password);

  // This doesn't count login failures towards account lockout
  // To enable password failures to trigger account lockout, change to shouldLockout: true
  var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
  switch (result)
  {
    case SignInStatus.Success:
      return RedirectToLocal(returnUrl);
    case SignInStatus.LockedOut:
      return View("Lockout");
    case SignInStatus.RequiresVerification:
      return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
    case SignInStatus.Failure:
    default:
      ModelState.AddModelError("", "Invalid login attempt.");
      return View(model);
  }
}

这是我的例行程序,从我的遗产dll获得“类似于足够映射”的答案:

private SignInStatus Login(string userId, string password)
{
  string SoftwareLicenses = "blahblahblah";
  try
  {
    UserCredentials = UserProfileType.Login(userId, password, 0, SoftwareLicenses);
    return SignInStatus.Success;
  }
  catch (AtlasBusinessRuleException abrex)
  {
    switch (abrex.Message)
    {
      case "Invalid Login Name entered":
        return SignInStatus.Failure;
      case "Invalid Password entered":
        return SignInStatus.Failure;
      case "Your password has expired. Please change the password.":
        return SignInStatus.LockedOut;
      default:
        return SignInStatus.Failure;
    }

  }
}

请参阅,如果我只是在样板例程中取消注释我对例程的调用,这还不足以打开我登录的所有.Net框架意识以及我是谁等等。我完全理解角色是不同的但是现在我已经满足于只是登录并让网站表现得就像我用它的代码那样。

更新

这可能与它在ApplicationUserManager的{​​{1}}文件中创建的ApplicationSignInManagerIdentityConfig有关。

ASP.NET MVC and Identity 2.0: Understanding the Basics

1 个答案:

答案 0 :(得分:0)

我使用了一种新方法来得出答案。我得出答案的方式比答案本身更重要。

发现答案的方法

enter image description here

  1. 找到.Net Framework源代码。在这种情况下,它是Microsoft.AspNet.Identity.CoreMicrosoft.AspNet.Identity.Owin
  2. 找到我想与之交互的“黑匣子”类。在这种情况下,它是UserManagerSignInManager
  3. 找到我想要互操作的条目“黑匣子”方法。在这种情况下,在SignInManager.PasswordSignInAsync()
  4. 中调用了AccountController.Login(LoginViewModel model, string returnUrl)
  5. 从源代码中复制方法并将其粘贴到样板子类中。在这种情况下,它是ApplicationSignInManager。将virtual关键字更改为override
  6. ,将方法转换为覆盖
  7. 找到并注释掉与我的后端dll不兼容的任何代码,或者只是不起作用或不适用于我的应用程序。不要过度评论或假设任何事情。保守评论。
  8. 如果我的后端dll需要提供功能,请使用我的后端dll提供。
  9. 如果这个“黑盒子方法”(我们刚刚制作了白盒子)调用任何更暗的方法,那么也要重复该方法的步骤4到6,依此类推,递归。无论是否进行调试,都可以执行此操作。我使用调试因为这比信任我的眼睛更容易遵循代码流程。
  10. 使用此方法的结果

    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)的知识,而不是我在几个小时的阅读或谷歌搜索中学到的。它可能不完美,但我可以使用相同的过程来改善我在这里所拥有的。