3

我们通过使用用户的凭据调用 web 服务并返回包含用户 ID 的 WCF 结构,即“LogonTicket”来覆盖 MVC3 应用程序中的基本身份验证。此 LogonTicket 用于“为对 Web 服务的每次调用验证用户。

现在,我们通过替换 Web.config 中的 defaultProvider 来覆盖。我们在这个被覆盖的提供者中所做的就是覆盖 ValidateUser() 函数。这就是我们使用他们的凭据调用 Web 服务并返回“LogonTicket”的地方。

这是 AccountController 中的 LogOn() 函数,本质上是模板中的基本代码:

public ActionResult LogOn(LogOnModel model)
{
    string ReturnUrl = "";
    if (HttpContext.Request.UrlReferrer.Query.Length > 11)
    {
        ReturnUrl = Uri.UnescapeDataString(HttpContext.Request.UrlReferrer.Query.Substring(11));
    }
    if (ModelState.IsValid)
    {
        if (Membership.ValidateUser(model.UserName, model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
            if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
                && !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
            {
                return Redirect(ReturnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
        }
    }

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

这是我们新的默认提供程序中重写的 ValidateUser() 函数:

public override bool ValidateUser(string username, string password)
{
    MyServiceClient mps = new MyServiceClient();
    string sha1password = HashCode(password);
    LogonInfo logonInfo = mps.GetLogonTicket(username, sha1password);
    if (logonInfo.LogonTicket != "" && logonInfo.LogonTicket != "0") 
    {
    // Authenticated so set session variables
        HttpContext.Current.Session["LogonTicket"] = logonInfo.LogonTicket;
        HttpContext.Current.Session["ParticipantID"] = logonInfo.ParticipantID;
        return true;
    }
    else
    {
        return false;
    }
}

我不确定如何结合使用两者,所以我的问题是:

  1. 如何实现 OpenID 和 Facebook 登录并保留当前的身份验证方法?
  2. 我们如何将 OpenID 用户与我们当前的用户 DB 值“映射”?我们必须知道这样我们才能检索他们的信息。我知道我们可以检索他们的电子邮件地址,但如果他们的 OpenID 电子邮件与他们在我们网站上用于记录的电子邮件不同怎么办?
  3. 是否有任何示例说明如何在任何地方执行此操作?

谢谢你看我的问题。

4

2 回答 2

3

我完成了一个需要多种登录可能性的项目(自定义帐户、Google 和 Facebook)

最后,您使用 ASP.NET 的身份验证完全取决于您的配置。(在您的情况下,它是 FormsAuthentication)这意味着FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);基本上确定了与您的用户有关的所有内容,并且您设置它的位置不受限制。

您现在与我们开始时的实现基本相同,使用 MembershipProvider 来处理您自己的自定义帐户。您现在只需要扩展以方便 openIds。您必须Controller为每种登录类型扩展各种操作(现在您ActionResult LogOn()可以添加到其中,例如:)ActionResult LogOnOpenId()。在该方法中,您基本上调用相同的代码,而不是Membership.ValidateUser(model.UserName, model.Password)调用 OpenId 服务。

我在下面提供了一个使用 dotnetopenauth 的 google 实现示例。服务方法使用formsService.SignIn(userId.Value.ToString(), false);基本调用的方法FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);(我们只对 SecurityPrincipal 进行一些自定义行为,但这不会影响您的身份验证过程)。您还可以看到我们在收到新用户时创建了一个新帐户。为了解决您的问题第 2 部分,我们实施了一个配置文件,如果您可以提供另一个登录名,该配置文件可以合并。这允许我们的用户保持他们的帐户合并并使用他们喜欢的任何登录方法。

关于多点登录的示例,我将参考 Tomas 的回答,他将 StackExchange 作为一个很好的示例。另外,我建议您安装 MVC4 和 VS2012,然后执行 File > New Project。MVC 的最新默认模板包括 openid 实现以及自定义登录!

谷歌 openid 实现示例:

控制器方法:

    public virtual ActionResult LoginGoogle(string returnUrl, string runAction)
    {
        using (var openId = new OpenIdRelyingParty())
        {
            IAuthenticationResponse response = openId.GetResponse();

            // If we have no response, start 
            if (response == null)
            {
                // Create a request and redirect the user 
                IAuthenticationRequest req = openId.CreateRequest(WellKnownProviders.Google);
                var fetch = new FetchRequest();
                fetch.Attributes.AddRequired(WellKnownAttributes.Name.First);
                fetch.Attributes.AddRequired(WellKnownAttributes.Name.Last);
                fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
                fetch.Attributes.AddRequired(WellKnownAttributes.Preferences.Language);
                req.AddExtension(fetch);

                req.RedirectToProvider();

                return null;
            }

            _service.ConnectViaGoogle(response, TempData);
    }

服务方式:

    public void ConnectViaGoogle(IAuthenticationResponse response, TempDataDictionary tempData)
    {
        // We got a response - check it's valid and that it's me 
        if (response.Status == AuthenticationStatus.Authenticated)
        {
            var claim = response.GetExtension<FetchResponse>();
            Identifier googleUserId = response.ClaimedIdentifier;
            string email = string.Empty;
            string firstName = string.Empty;
            string lastName = string.Empty;
            string language = string.Empty;

            if (claim != null)
            {
                email = claim.GetAttributeValue(WellKnownAttributes.Contact.Email);
                firstName = claim.GetAttributeValue(WellKnownAttributes.Name.First);
                lastName = claim.GetAttributeValue(WellKnownAttributes.Name.Last);
                language = claim.GetAttributeValue(WellKnownAttributes.Preferences.Language);
            }

            //Search User with google UserId
            int? userId = _userBL.GetUserIdByGoogleSingleSignOnId(googleUserId);

            //if not exists -> Create
            if (!userId.HasValue)
            {
                _userBL.CreateGoogleUser(
                    googleUserId,
                    firstName,
                    lastName,
                    email,
                    language,
                    DBConstants.UserStatus.DefaultStatusId,
                    out userId);
            }

            if (userId.HasValue)
            {
                _userBL.UpdateLastLogon(userId.Value);
                var formsService = new FormsAuthenticationService();
                formsService.SignIn(userId.Value.ToString(), false);
                AfterLoginActions(tempData);
            }
        }
    }

有任何问题或意见吗?我很乐意听到他们的声音。

于 2012-11-14T13:53:10.583 回答
1
  1. 完全有可能拥有多种身份验证方法。所有 IIS / ASP.net 关心的是 FormsAuthentication cookie。因此,您将为标准用户名/密码身份验证设置一组操作,并为 OpenId 设置另一组操作。这至少是我在一个项目中所做的。
  2. 你甚至不能相信 openId 提供商会给你一个电子邮件地址!这个问题的一个常见解决方案是允许用户在登录后将多个 OpenId 标识符 (URI) 附加到他的帐户。这就是 StackOverflow 的工作方式。如果这是用户第一次访问系统,那么您可以自动创建一个新帐户,或强制用户完成注册过程。
    当我在提到的系统中添加 OpenId 支持时,它有一个用于存储用户名和密码的现有表(用户表)。我添加了一个与 users 表具有多对一关系的新表,并使用它来存储 URI。
  3. 正如上面提到的 StackOverflow 本身是一个很好的起点,在http://www.dotnetopenauth.net/项目中也有很多很好的例子。据我所知,SO 的来源不是公开的,他们正在使用 dotnetopenauth 项目。
    这可能是抽象的,但这个库是开源果园 CMS 的 openId(除其他外):http: //orchardopenauth.codeplex.com/

我希望这会有所帮助,但如果您有任何问题,请详细说明您的问题。

于 2012-11-14T09:56:43.617 回答