身份验证工作流程有两个主要问题需要克服。一个,正如 OP 正确指出的那样,涉及内容,ExtraData
另一个涉及您需要向 Facebook 请求的权限。最后,我选择了DotNetOpenAuth
库而不是微软的库,但通过滚动我自己的类并在必要时借用部分框架,在某些地方扩展了它。
我做的第一件事是创建一个FacebookClient
扩展OAuth2Client
fromDotNetOpenAuth
并允许我传递一个值 for scope
,它超越了您可以从 Facebook 请求哪些数据的限制。我要求的许可是publish_stream, manage_pages, email, user_interests
. 它们只需附加到服务登录 URL 并传递给 Facebook。我的实现中有用的方法OAuth2Client
是GetUserData
:
protected override IDictionary<string, string> GetUserData(string accessToken)
{
var token = accessToken.EscapeUriDataStringRfc3986();
FacebookGraphData graphData;
var request = WebRequest.Create(string.Format("https://graph.facebook.com/me?access_token={0}", token));
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
graphData = JsonHelper.Deserialize<FacebookGraphData>(responseStream);
}
}
var userData = new Dictionary<string, string> {{"accessToken", accessToken}};
userData.AddItemIfNotEmpty("id", graphData.Id);
userData.AddItemIfNotEmpty("name", graphData.Name);
userData.AddItemIfNotEmpty("email", graphData.Email);
userData.AddItemIfNotEmpty("firstName", graphData.FirstName);
userData.AddItemIfNotEmpty("lastName", graphData.LastName);
userData.AddItemIfNotEmpty("link", graphData.Link == null ? null : graphData.Link.AbsoluteUri);
userData.AddItemIfNotEmpty("username", graphData.Username);
userData.AddItemIfNotEmpty("gender", graphData.Gender);
userData.AddItemIfNotEmpty("locale", graphData.Locale);
FacebookFriendData friendData;
request = WebRequest.Create(string.Format("https://graph.facebook.com/me/friends?access_token={0}", token));
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
friendData = JsonHelper.Deserialize<FacebookFriendData>(responseStream);
}
}
if (friendData.Friends != null)
{
userData.Add("connections", friendData.Friends.Count().ToString());
}
return userData;
}
我基本上创建了一些数据类,当响应从 Facebook 返回时,这些数据类会被反序列化。我还可以从这里进行我需要的任何其他 Graph API 调用。序列化类如下所示:
[DataContract]
public class FacebookFriendData
{
[DataMember(Name = "data")]
public IEnumerable<Friend> Friends { get; set; }
}
[DataContract]
public class Friend
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
}
[DataContract]
public class FacebookGraphData
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "email")]
public string Email { get; set; }
[DataMember(Name = "first_name")]
public string FirstName { get; set; }
[DataMember(Name = "last_name")]
public string LastName { get; set; }
[DataMember(Name = "link")]
public Uri Link { get; set; }
[DataMember(Name = "username")]
public string Username { get; set; }
[DataMember(Name = "gender")]
public string Gender { get; set; }
[DataMember(Name = "locale")]
public string Locale { get; set; }
}
根据@radm4,我仍然检查提供程序字符串以决定在某些地方调用哪些方法 - 仍在为该方法开发更优雅的解决方案......