【问题标题】:Using OpenID/OpenAuth in MVC3 app with overridden authentication method在 MVC3 应用程序中使用 OpenID/OpenAuth 并覆盖身份验证方法
【发布时间】:2012-10-20 04:28:24
【问题描述】:

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

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

这是来自我们 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. 是否有任何示例说明如何在任何地方执行此操作?

感谢您查看我的问题。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 oauth openid dotnetopenauth


    【解决方案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/

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

    【讨论】:

    • 1:太好了。 2:所以我需要为特定用户存储 OpenID 标识符? 3:代码是否可以显示它是如何做到的?
    【解决方案2】:

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

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

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

    我在下面提供了一个使用 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 实现以及自定义登录!

    google 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);
                }
            }
        }
    

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

    【讨论】:

    • 我建议你安装 MVC4 和 VS2012 我可以转换这个 MVC3 项目而不会头疼吗?
    • 所以您将 OpenID 标识符存储在外部表中并使用服务查找它们?
    • @MB34 MVC3 和 MVC4 之间的差异不如 2 和 3 之间的一些变化那么具有破坏性。您应该能够几乎完全复制粘贴它。当我从 MVC3-4 迁移时,最大的问题是获得所有项目引用的正确程序集。
    • @MB34 我们将 openId 标识符与我们的用户数据一起存储,以便我们可以识别回头客和夫妻帐户,以便人们可以使用他们的 openid 或他们的自定义帐户用户名和密码登录。 (我们的数据库为此目的有FacebookSingleSignOnIdGoogleSingleSignOnId 列)
    猜你喜欢
    • 2012-09-16
    • 1970-01-01
    • 2011-05-10
    • 2019-01-28
    • 2012-10-12
    • 1970-01-01
    • 2016-03-27
    • 2012-06-17
    • 2012-10-31
    相关资源
    最近更新 更多