如何在 MVC 5.0 C# 中从 facebook OAuth 获取 first_name 和 last_name?
how to get first_name and last_name from facebook OAuth in MVC 5.0 C#?
我需要从 Facebook v2_5 OAuth 获取 first_name 和 last_name。在 C# 中,MVC 5.I 正在使用 Microsoft.Owin.Security.Facebook 3.0.1.0.
`var record = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:name");`
我正在使用它获取名称,但我需要分别使用 first_name 和 last_name。
任何帮助都会提前appreciated.Thanks。
它叫做 "Declarative Fields",请参阅 v2.4 的更新日志:https://developers.facebook.com/docs/graph-api/changelog/archive#v2_4_new_features
这将是获取 first_name
和 last_name
:
的 API 调用
/me?fields=name,first_name,last_name
仅使用端点是不够的,事实证明对于当前的 OWIN Facebook 库 3.1.0 是不必要的 - 您现在可以在传递的选项中指定字段。
我必须使用自定义身份验证提供程序来解决 OWIN Facebook 库中的问题,其中 Facebook returns 字段,但 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、电子邮件、名称、first_name、last_name - 而不是传递自定义端点。我也指定了自定义 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 库未能解析出这些值,将它们作为声明存放在 loginInfo 用户对象中。
最后,为方便起见,我使用最后一个 class 以规范的方式跨提供商获取这些值,因为不同的提供商使用不同的模式提供名字和姓氏:
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;
Chris 的回答略有不同。诀窍是添加具有众所周知类型的声明,该声明从 Facebook 发送的 first_name
和 last_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);
我需要从 Facebook v2_5 OAuth 获取 first_name 和 last_name。在 C# 中,MVC 5.I 正在使用 Microsoft.Owin.Security.Facebook 3.0.1.0.
`var record = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:name");`
我正在使用它获取名称,但我需要分别使用 first_name 和 last_name。 任何帮助都会提前appreciated.Thanks。
它叫做 "Declarative Fields",请参阅 v2.4 的更新日志:https://developers.facebook.com/docs/graph-api/changelog/archive#v2_4_new_features
这将是获取 first_name
和 last_name
:
/me?fields=name,first_name,last_name
仅使用端点是不够的,事实证明对于当前的 OWIN Facebook 库 3.1.0 是不必要的 - 您现在可以在传递的选项中指定字段。
我必须使用自定义身份验证提供程序来解决 OWIN Facebook 库中的问题,其中 Facebook returns 字段,但 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、电子邮件、名称、first_name、last_name - 而不是传递自定义端点。我也指定了自定义 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 库未能解析出这些值,将它们作为声明存放在 loginInfo 用户对象中。
最后,为方便起见,我使用最后一个 class 以规范的方式跨提供商获取这些值,因为不同的提供商使用不同的模式提供名字和姓氏:
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;
Chris 的回答略有不同。诀窍是添加具有众所周知类型的声明,该声明从 Facebook 发送的 first_name
和 last_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);