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

4

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

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

问题:API的大多数使用者将来自于我的Web应用程序的客户。

我不希望一个客户端有两个密码,一个用于Web应用程序,一个用于API。

如何与其他项目共享Web应用程序(MVC5)数据库?例如WCF。

我需要在我的WCF中实现两种方法,这两种方法会与Web应用程序完全相同:

  • 注册。
  • 登录。

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

注册:

 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

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


那么您建议创建一个新的数据库(身份数据库),并将这两个组件指向新数据库吗?如果下个月我想将另一个组件整合到数据库中,比如Web API呢?我还需要再创建一个新的数据库吗? - Ron
我不确定我理解了。你的问题主要是关于在不同项目(Web API,WCF等)之间共享身份,并如何实现这一点。如果需要,所有应用程序都可以共享相同的身份和应用程序数据数据库。 - Nathan Fisher

0

阅读了几篇文章后,我理解了密码验证器的工作原理,并在微软开源代码的帮助下成功构建了一个处理密码验证的类。

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密码验证算法背后的思想是:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接