【问题标题】:how to get first_name and last_name from facebook OAuth in MVC 5.0 C#?如何在 MVC 5.0 C# 中从 facebook OAuth 获取 first_name 和 last_name?
【发布时间】:2016-03-18 06:08:49
【问题描述】:

我需要从 Facebook v2_5 OAuth 获取 first_name 和 last_name。在 C#、MVC 5 中。我使用的是 Microsoft.Owin.Security.Facebook 3.0.1.0。

`var record = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:name");`

我通过使用它来获取名称,但我需要分别使用 first_name 和 last_name。 任何帮助将不胜感激。在此先感谢。

【问题讨论】:

    标签: c# asp.net asp.net-mvc oauth-2.0 facebook-oauth


    【解决方案1】:

    它被称为“声明性字段”,请参阅 v2.4 的变更日志:https://developers.facebook.com/docs/graph-api/changelog/archive#v2_4_new_features

    这将是获取first_namelast_name 的API 调用:

    /me?fields=name,first_name,last_name
    

    【讨论】:

    • 感谢您的宝贵时间,我已应用这些更改仍然没有成功
    • 在 api explorer 中工作正常:developers.facebook.com/tools/explorer/…
    • 谢谢,对我的代码进行了更改,它解决了我的问题,
    【解决方案2】:

    仅使用端点是不够的,而且对于当前的 OWIN Facebook 库 3.1.0 来说是不必要的 - 您现在可以在传递的选项中指定字段。

    我必须使用自定义身份验证提供程序来解决 OWIN Facebook 库中的问题,Facebook 会在其中返回字段,但 OWIN 库无法为您解析和收集它们。我怀疑这是因为 lib 的设计是为了让您提出索赔,然后检索对该索赔的响应;但是如果你只是命名一个字段,由于某种原因它根本不会解析出来。

    在 Startup.Auth 中:

    var facebook = new FacebookAuthenticationOptions
    {
        Provider = Brass9.OwinVisitor.Auth.Facebook.
            FirstLastNameFacebookAuthenticationProvider.SplitFirstLastName(),
    #if DEBUG
        AppId = //
        AppSecret = //
    #else
        AppId = //
        AppSecret = //
    #endif
    };
    //id,name,email,first_name,last_name
    var fbScope = facebook.Scope;
    fbScope.Add("email");
    //fbScope.Add("first_name");    // Uncommenting this line will break auth
    facebook.Fields.Add("id");
    facebook.Fields.Add("email");
    facebook.Fields.Add("name");
    facebook.Fields.Add("first_name");
    facebook.Fields.Add("last_name");
    app.UseFacebookAuthentication(facebook);
    

    所以,到目前为止,我已经使用新的 OWIN 字段选项来指定 id、电子邮件、姓名、名字、姓氏 - 而不是传入自定义端点。我还指定了自定义 AuthenticationProvider。这里是:

    namespace Brass9.OwinVisitor.Auth.Facebook
    {
        public static class FirstLastNameFacebookAuthenticationProvider
        {
            public static FacebookAuthenticationProvider SplitFirstLastName()
            {
                return new FacebookAuthenticationProvider
                {
    OnAuthenticated = async context =>
    {
        context.Identity.AddClaim(new System.Security.Claims.Claim(
            "FacebookAccessToken", context.AccessToken));
        foreach (var claim in context.User)
        {
            var claimType = string.Format("urn:facebook:{0}", claim.Key);
            string claimValue = claim.Value.ToString();
    
            if (!context.Identity.HasClaim(claimType, claimValue))
                context.Identity.AddClaim(new System.Security.Claims.Claim(
                    claimType, claimValue, "XmlSchemaString", "Facebook"));
        }
    }
                };
            }
        }
    }
    

    这弥补了 OWIN lib 未能解析出这些值,将它们作为声明存放在 loginInfo 用户对象中。

    最后,为了方便起见,我使用最后一个类以规范的方式跨提供者获取这些值,因为不同的提供者使用不同的模式提供名字和姓氏:

    namespace Brass9.OwinVisitor.Auth
    {
        public class ReducedClaims
        {
            protected Dictionary<string, string> claims;
    
            public ReducedClaims(IEnumerable<System.Security.Claims.Claim> claims)
            {
                var _claims = claims.ToArray();
                this.claims = new Dictionary<string, string>(_claims.Length);
    
                foreach(var claim in _claims)
                {
                    this.claims.Add(claim.Type, claim.Value);
                }
            }
    
            public ReducedClaims(ExternalLoginInfo loginInfo)
                : this(loginInfo.ExternalIdentity.Claims)
            {}
    
            //http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
            //http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
    
    
    
            protected string chainValue(params string[] keys)
            {
                string val = null;
                foreach(var key in keys)
                {
                    if (claims.TryGetValue(key, out val))
                        return val;
                }
    
                return val;
            }
    
            // TODO: Instead detect which service it is then use the proper string instead of just milling through guesses?
            public string FirstName { get { return chainValue(
                "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",  // Google
                "urn:facebook:first_name"   // Facebook
            ); } }
    
            public string LastName { get { return chainValue(
                "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",    // Google
                "urn:facebook:last_name"    // Facebook
            ); } }
        }
    }
    

    你可以这样称呼:

    var reducedClaims = new ReducedClaims(loginInfo.ExternalIdentity.Claims);
    var firstName = reducedClaims.FirstName;
    var lastName = reducedClaims.LastName;
    

    【讨论】:

      【解决方案3】:

      克里斯的回答略有不同。诀窍是使用从 Facebook 发送的 first_namelast_name 字段中获取值的知名类型添加声明。出于某种原因,Microsoft library 没有这样做。

      var facebookOptions = new FacebookAuthenticationOptions
      {
          AppId = "*",
          AppSecret = "*",
      };
      const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
      facebookOptions.Provider = new FacebookAuthenticationProvider
      {
          OnAuthenticated = context =>
          {
              void addClaim(
                  FacebookAuthenticatedContext ctx,
                  string faceBookClaim,
                  string aspNetClaim)
              {
                  if (context.User.TryGetValue(faceBookClaim, out JToken t))
                  {
                      ctx.Identity.AddClaim(
                          new Claim(
                              aspNetClaim,
                              t.ToString(),
                              XmlSchemaString,
                              facebookOptions.AuthenticationType));
                  }
              }
      
              addClaim(context, "first_name", ClaimTypes.GivenName);
              addClaim(context, "last_name", ClaimTypes.Surname);
              return Task.CompletedTask;
          }
      };
      
      facebookOptions.Scope.Add("public_profile");
      facebookOptions.Scope.Add("email");
      
      facebookOptions.Fields.Add("email");
      facebookOptions.Fields.Add("name");
      facebookOptions.Fields.Add("first_name");
      facebookOptions.Fields.Add("last_name");
      app.UseFacebookAuthentication(facebookOptions);
      

      【讨论】:

        猜你喜欢
        • 2016-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多