身份验证工作流程有两个主要问题需要克服。一个,正如 OP 正确指出的那样,涉及ExtraData 的内容,另一个涉及您需要向 Facebook 请求的权限。最后,我选择了DotNetOpenAuth 库而不是 Microsoft 库,但通过滚动我自己的类并在必要时借用部分框架,在某些地方扩展了它。
我做的第一件事是创建一个FacebookClient,它从DotNetOpenAuth 扩展了OAuth2Client,并允许我为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,我仍然检查提供程序字符串以决定在某些地方调用哪些方法 - 仍在为该方法提供更优雅的解决方案...