从外部项目连接到现有的MVC 5 DB(身份模型)

时间:2015-05-13 23:16:24

标签: c# asp.net-mvc entity-framework web-services asp.net-identity

背景:我有一个为我的客户提供服务的网络应用程序。

动机:现在我想借助API(WCF和Web API)来公开该服务。该服务的消费者需要进行身份验证。

问题: API的大多数消费者都来自我的网络应用客户。

我不希望一个客户端有2个密码,一个用于Web App,另一个用于API。

如何与其他项目共享Web App(MVC5)数据库?,例如WCF。

我需要在我的WCF中运行两个与Web App完全相同的方法:

  • 注册。
  • 登录。

这个方法在我的项目中实现如下:

注册

 public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.UserName, Email = model.Email, OrganizationID = "10", DateJoin = DateTime.Now, LockoutEndDateUtc=DateTime.UtcNow.AddYears(5),LockoutEnabled=false};
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {

                IdentityResult resultClaim = await UserManager.AddClaimAsync(user.Id, new Claim("OrgID", "10"));

                if(resultClaim.Succeeded)
                {
                    UserManager.AddToRole(user.Id, "guest");
                    await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
                    return RedirectToAction("Index", "Home");
                }


            }
            AddErrors(result);
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

登录

  public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {

        if (!ModelState.IsValid || User.Identity.IsAuthenticated)
        {
            return View(model);
        }

        // 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.UserName, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
           case SignInStatus.Success:
                Session["Timezone"] = model.offSet;
                    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);
        }
    }

2 个答案:

答案 0 :(得分:0)

您可以创建单独的身份数据库,并让所有用户对其进行身份验证。创建UserManager / RoleManager等时,可以将连接字符串指向标识数据库

答案 1 :(得分:0)

在阅读了几篇文章后,我了解了密码验证程序的工作原理,并且在Microsoft的开源代码的帮助下,我设法构建了一个负责密码验证的类。

UserValidation类:

 public class UserValidation 
{
    public override void Validate(string userName, string password)
    {
        if (null == userName || null == password)
        {
            throw new ArgumentNullException();
        }

        string hashPassword = DataQueries.GetHashPassword(userName);

        if (!VerifyHashedPassword(hashPassword, password))
            throw new FaultException("Unknown Username or incorrect Password");

    }

    private static string HashPassword(string password)
    {
        byte[] salt;
        byte[] buffer2;
        if (password == null)
        {
            throw new ArgumentNullException("password");
        }
        using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, 0x10, 0x3e8))
        {
            salt = bytes.Salt;
            buffer2 = bytes.GetBytes(0x20);
        }
        byte[] dst = new byte[0x31];
        Buffer.BlockCopy(salt, 0, dst, 1, 0x10);
        Buffer.BlockCopy(buffer2, 0, dst, 0x11, 0x20);
        return Convert.ToBase64String(dst);
    }

    private static bool VerifyHashedPassword(string hashedPassword, string password)
    {
        byte[] buffer4;
        if (hashedPassword == null)
        {
            return false;
        }
        if (password == null)
        {
            throw new ArgumentNullException("password");
        }
        byte[] src = Convert.FromBase64String(hashedPassword);
        if ((src.Length != 0x31) || (src[0] != 0))
        {
            return false;
        }
        byte[] dst = new byte[0x10];
        Buffer.BlockCopy(src, 1, dst, 0, 0x10);
        byte[] buffer3 = new byte[0x20];
        Buffer.BlockCopy(src, 0x11, buffer3, 0, 0x20);
        using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, dst, 0x3e8))
        {
            buffer4 = bytes.GetBytes(0x20);
        }
        return ByteArraysEqual(buffer3, buffer4);
    }

    private static bool ByteArraysEqual(byte[] b1, byte[] b2)
    {
        if (b1 == b2) return true;
        if (b1 == null || b2 == null) return false;
        if (b1.Length != b2.Length) return false;
        for (int i = 0; i < b1.Length; i++)
        {
            if (b1[i] != b2[i]) return false;
        }
        return true;
    }

Microsoft密码验证算法背后的理念是:

存储在DB中的字符串包含带有salt的密码的哈希值,这是一个示例: 我们在DB中有一个字符串:123456789,字符串的一部分是哈希密码,部分是盐,在我们的例子中,假设123456是哈希密码而789是盐。 (在Microsoft算法中,保存salt的字符数始终相同,但可以手动更改)