asp.net-mvc 如何使用 ASP.NET Identity (OWIN) 访问 Facebook 私人信息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18942196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to access Facebook private information by using ASP.NET Identity (OWIN)?
提问by Konamiman
I am developing a web site in ASP.NET MVC 5 (using RC1 version currently). The site will use Facebook for user authentication and for retrieving initial profile data.
我正在 ASP.NET MVC 5 中开发一个网站(目前使用 RC1 版本)。该网站将使用 Facebook 进行用户身份验证和检索初始配置文件数据。
For the authentication system I am using the new OWIN based ASP.NET Identity engine (http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-forms-authentication-in-mvc-5.aspx), since it greatly simplifies the process of authenticating with external providers.
对于身份验证系统,我使用新的基于 OWIN 的 ASP.NET 身份引擎 ( http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-forms-authentication-in-mvc -5.aspx),因为它极大地简化了与外部提供商进行身份验证的过程。
The problem is that once a user first logs in, I want to get its email address from the Facebook profile, but this data is not included in the generated claims. So I have thought on these alternatives to get the address:
问题是,一旦用户首次登录,我想从 Facebook 个人资料中获取其电子邮件地址,但此数据未包含在生成的声明中。所以我想过这些替代方法来获取地址:
Instruct the ASP.NET Identity engine to include the email address in the set of data that is retrieved from Facebook and then converted to claims. I don't know if this is possible at all.
Use the Facebook graph API (https://developers.facebook.com/docs/getting-started/graphapi) to retrieve the email address by using the Facebook user id (which is included in the claims data). But this will not work if the user has set his email address as private.
Use the Facebook graph API, but specifying "me" instead of the Facebook user id (https://developers.facebook.com/docs/reference/api/user). But an access token is required, and I don't know how to (or if it's possible at all) retrieve the access token that ASP.NET uses to obtain the user data.
指示 ASP.NET 标识引擎在从 Facebook 检索然后转换为声明的数据集中包含电子邮件地址。我不知道这是否可能。
使用 Facebook 图形 API ( https://developers.facebook.com/docs/getting-started/graphapi) 通过使用 Facebook 用户 ID(包含在声明数据中)检索电子邮件地址。但是如果用户将他的电子邮件地址设置为私人,这将不起作用。
使用 Facebook 图形 API,但指定“我”而不是 Facebook 用户 ID ( https://developers.facebook.com/docs/reference/api/user)。但是需要访问令牌,我不知道如何(或者根本不知道)检索 ASP.NET 用于获取用户数据的访问令牌。
So the question is:
所以问题是:
How can I instruct the ASP.NET Identity engine to retrieve additional information from Facebook and include it in the claims data?
Or alternatively, how can I retrieve the generated access token so that I can ask Facebook myself?
如何指示 ASP.NET Identity 引擎从 Facebook 检索附加信息并将其包含在声明数据中?
或者,我如何检索生成的访问令牌,以便我可以自己询问 Facebook?
Thank you!
谢谢!
Note: for the authentication system my application uses code based on the sample project linked in this SO answer: https://stackoverflow.com/a/18423474/4574
注意:对于身份验证系统,我的应用程序使用基于此 SO 答案中链接的示例项目的代码:https: //stackoverflow.com/a/18423474/4574
采纳答案by Praburaj
To retrieve additional information from facebook you can specify scopes you would like to include when you configure the facebook authentication options. Getting the additional information that's retrieved can be achieved by implementing the provider's OnAuthenticated method like this:
要从 facebook 检索其他信息,您可以指定在配置 facebook 身份验证选项时要包含的范围。可以通过实现提供者的 OnAuthenticated 方法来获取检索到的附加信息,如下所示:
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
{
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
// All data from facebook in this object.
var rawUserObjectFromFacebookAsJson = context.User;
// Only some of the basic details from facebook
// like id, username, email etc are added as claims.
// But you can retrieve any other details from this
// raw Json object from facebook and add it as claims here.
// Subsequently adding a claim here will also send this claim
// as part of the cookie set on the browser so you can retrieve
// on every successive request.
context.Identity.AddClaim(...);
return Task.FromResult(0);
}
}
};
//Way to specify additional scopes
facebookOptions.Scope.Add("...");
app.UseFacebookAuthentication(facebookOptions);
Per the code herei see the email is already retrieved and added as a claim here if facebook has sent. Are you not able to see it?
回答by John Palmer
Create a new Microsoft.Owin.Security.Facebook.AuthenticationOptions object in Startup.ConfigureAuth (StartupAuth.cs), passing it the FacebookAppId, FacebookAppSecret, and a new AuthenticationProvider. You will use a lambda expression to pass the OnAuthenticated method some code to add Claims to the identity which contain the values you extract from context.Identity. This will include access_tokenby default. You must add emailto the Scope. Other user properties are available from context.User (see link at bottom for example).
在 Startup.ConfigureAuth (StartupAuth.cs) 中创建一个新的 Microsoft.Owin.Security.Facebook.AuthenticationOptions 对象,将 FacebookAppId、FacebookAppSecret 和一个新的 AuthenticationProvider 传递给它。您将使用 lambda 表达式向 OnAuthenticated 方法传递一些代码,以将 Claims 添加到包含您从 context.Identity 中提取的值的标识。默认情况下,这将包括access_token。您必须将电子邮件添加到范围。其他用户属性可从 context.User 获得(例如,请参见底部的链接)。
StartUp.Auth.cs
启动.Auth.cs
// Facebook : Create New App
// https://dev.twitter.com/apps
if (ConfigurationManager.AppSettings.Get("FacebookAppId").Length > 0)
{
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
{
AppId = ConfigurationManager.AppSettings.Get("FacebookAppId"),
AppSecret = ConfigurationManager.AppSettings.Get("FacebookAppSecret"),
Provider = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, XmlSchemaString, "Facebook"));
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:email", context.Email, XmlSchemaString, "Facebook"));
return Task.FromResult(0);
}
}
};
facebookOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookOptions);
}
In AccountController, I extract the ClaimsIdentity from the AuthenticationManager using the external cookie. I then add it to the identity created using the application cookie. I ignored any claims that starts with "...schemas.xmlsoap.org/ws/2005/05/identity/claims" since it seemed to break the login.
在 AccountController 中,我使用外部 cookie 从 AuthenticationManager 中提取 ClaimsIdentity。然后我将它添加到使用应用程序 cookie 创建的身份中。我忽略了以“...schemas.xmlsoap.org/ws/2005/05/identity/claims”开头的任何声明,因为它似乎破坏了登录。
AccountController.cs
账户控制器.cs
private async Task SignInAsync(CustomUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// Extracted the part that has been changed in SignInAsync for clarity.
await SetExternalProperties(identity);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
private async Task SetExternalProperties(ClaimsIdentity identity)
{
// get external claims captured in Startup.ConfigureAuth
ClaimsIdentity ext = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
if (ext != null)
{
var ignoreClaim = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims";
// add external claims to identity
foreach (var c in ext.Claims)
{
if (!c.Type.StartsWith(ignoreClaim))
if (!identity.HasClaim(c.Type, c.Value))
identity.AddClaim(c);
}
}
}
And finally, I want to display whatever values are not from the LOCAL AUTHORITY. I created a partial view _ExternalUserPropertiesListPartial that appears on the /Account/Manage page. I get the claims I previously stored from AuthenticationManager.User.Claims and then pass it to the view.
最后,我想显示不是来自 LOCAL AUTHORITY 的任何值。我创建了一个局部视图 _ExternalUserPropertiesListPartial,它出现在/Account/Manage 页面上。我从 AuthenticationManager.User.Claims 获取我之前存储的声明,然后将其传递给视图。
AccountController.cs
账户控制器.cs
[ChildActionOnly]
public ActionResult ExternalUserPropertiesList()
{
var extList = GetExternalProperties();
return (ActionResult)PartialView("_ExternalUserPropertiesListPartial", extList);
}
private List<ExtPropertyViewModel> GetExternalProperties()
{
var claimlist = from claims in AuthenticationManager.User.Claims
where claims.Issuer != "LOCAL AUTHORITY"
select new ExtPropertyViewModel
{
Issuer = claims.Issuer,
Type = claims.Type,
Value = claims.Value
};
return claimlist.ToList<ExtPropertyViewModel>();
}
And just to be thorough, the view:
只是为了彻底,观点:
_ExternalUserPropertiesListPartial.cshtml
_ExternalUserPropertiesListPartial.cshtml
@model IEnumerable<MySample.Models.ExtPropertyViewModel>
@if (Model != null)
{
<legend>External User Properties</legend>
<table class="table">
<tbody>
@foreach (var claim in Model)
{
<tr>
<td>@claim.Issuer</td>
<td>@claim.Type</td>
<td>@claim.Value</td>
</tr>
}
</tbody>
</table>
}
The working example and complete code is on GitHub: https://github.com/johndpalm/IdentityUserPropertiesSample
工作示例和完整代码位于 GitHub 上:https: //github.com/johndpalm/IdentityUserPropertiesSample
And any feedback, corrections, or improvements would be appreciated.
任何反馈、更正或改进将不胜感激。
回答by Julien
It worked for me with just this in Startup.Auth:
它对我有用Startup.Auth:
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions() {
AppId = "*",
AppSecret = "**"
};
facebookOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookOptions);
And then in the method ExternalLoginCallbackor ExternalLoginConfirmationyou get the email with :
然后在方法中ExternalLoginCallback或者ExternalLoginConfirmation你会收到带有以下内容的电子邮件:
ClaimsIdentity ext = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var email = ext.Claims.First(x => x.Type.Contains("emailaddress")).Value;
回答by BrunoLM
You need to create an instance of FacebookAuthenticationOptionsand configurethe Provider. The Providercontains an event called OnAuthenticatedthat is triggered when you login.
您需要创建一个实例FacebookAuthenticationOptions并配置Provider. 在Provider包含所谓的事件OnAuthenticated,当你登录时被触发。
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions
{
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, ClaimValueTypes.String, "Facebook"));
return Task.FromResult(0);
}
},
// You can store these on AppSettings
AppId = ConfigurationManager.AppSettings["facebook:AppId"],
AppSecret = ConfigurationManager.AppSettings["facebook:AppSecret"]
};
app.UseFacebookAuthentication(facebookOptions);
In the above code I am accessing the access_tokenby context.AccessTokenand add it to Claimsof the current loggedin user.
在上面的代码中,我正在访问access_tokenbycontext.AccessToken并将其添加到Claims当前登录用户的。
To access this value later you need to do this:
要稍后访问此值,您需要执行以下操作:
var owinContext = HttpContext.GetOwinContext();
var authentication = owinContext.Authentication;
var user = autentication.User;
var claim = (user.Identity as ClaimsIdentity).FindFirst("urn:facebook:access_token");
string accessToken;
if (claim != null)
accessToken = claim.Value;
To simplify all of this, you can create a BaseControllerand make all your Controllersinherit from it.
为了简化所有这些,您可以创建一个BaseController并从中Controllers继承所有内容。
The BaseControllercode would be:
该BaseController代码将是:
public class BaseController : Controller
{
public IOwinContext CurrentOwinContext
{
get
{
return HttpContext.GetOwinContext();
}
}
public IAuthenticationManager Authentication
{
get
{
return CurrentOwinContext.Authentication;
}
}
public new ClaimsPrincipal User
{
get
{
return Authentication.User;
}
}
public ClaimsIdentity Identity
{
get
{
return Authentication.User.Identity as ClaimsIdentity;
}
}
public string FacebookAccessToken
{
get
{
var claim = Identity.FindFirst("urn:facebook:access_token");
if (claim == null)
return null;
return claim.Value;
}
}
}
Then to get the access token on your code you just need to access the property FacebookAccessToken.
然后要在您的代码上获取访问令牌,您只需要访问该属性FacebookAccessToken。
string accessToken = FacebookAccessToken;
It is possible to retrieve some other values as
可以检索其他一些值作为
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:username",
context.User.Value<string>("username"), ClaimValueTypes.String, "Facebook"));
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:name",
context.User.Value<string>("name"), ClaimValueTypes.String, "Facebook"));
Note that not all fields will be available, to get the email you need to require the Scopeemail.
请注意,并非所有字段都可用,要获取需要Scope电子邮件的电子邮件。
facebookOptions.Scope.Add("email");
Then access on the OnAuthenticatedevent as
然后访问OnAuthenticated事件作为
context.User.Value<string>("email");
回答by pranav rastogi
Here are some steps which will help you. I am in the process of writing up a blog post but it will take a while... - Add Scopes in Fb provider and add the data returned from FB as claims
以下是一些可以帮助您的步骤。我正在写一篇博客文章,但需要一段时间...... - 在 Fb 提供程序中添加范围并将从 FB 返回的数据添加为声明
app.UseFacebookAuthentication(new FacebookAuthenticationOptions()
{
AppId = "",
AppSecret = "",
//Scope = "email,user_about_me,user_hometown,friends_about_me,friends_photos",
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = async context =>
{
foreach (var x in context.User)
{
context.Identity.AddClaim(new System.Security.Claims.Claim(x.Key, x.Value.ToString()));
}
//Get the access token from FB and store it in the database and use FacebookC# SDK to get more information about the user
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
}
},
SignInAsAuthenticationType = "External",
});
Use the Access Token and call Facebook C# SDK to get the list of friends for the user
var claimsIdentity = HttpContext.User.Identity as ClaimsIdentity; var access_token = claimsIdentity.FindAll("FacebookAccessToken").First().Value; var fb = new FacebookClient(access_token); dynamic myInfo = fb.Get("/me/friends"); var friendsList = new List<FacebookViewModel>(); foreach (dynamic friend in myInfo.data) { friendsList.Add(new FacebookViewModel() { Name = friend.name, ImageURL = @"https://graph.facebook.com/" + friend.id + "/picture?type=large" }); //Response.Write("Name: " + friend.name + "<br/>Facebook id: " + friend.id + "<br/><br/>"); }
使用 Access Token 并调用 Facebook C# SDK 获取用户的好友列表
var claimsIdentity = HttpContext.User.Identity as ClaimsIdentity; var access_token = claimsIdentity.FindAll("FacebookAccessToken").First().Value; var fb = new FacebookClient(access_token); dynamic myInfo = fb.Get("/me/friends"); var friendsList = new List<FacebookViewModel>(); foreach (dynamic friend in myInfo.data) { friendsList.Add(new FacebookViewModel() { Name = friend.name, ImageURL = @"https://graph.facebook.com/" + friend.id + "/picture?type=large" }); //Response.Write("Name: " + friend.name + "<br/>Facebook id: " + friend.id + "<br/><br/>"); }
回答by Mr. Pumpkin
my couple cents to all answers... if you still want to ask Facebook yourself, it makes sense to take a look on already existing Facebookpackage. It provides some great functionality that already implemented, so you don't have to re-implement it yourself... some example how to use it inside ASP.NET MVC application you can find here.
我对所有答案都付出了几分钱......如果你仍然想自己问 Facebook,看看已经存在的Facebook包是有意义的。它提供了一些已经实现的很棒的功能,因此您不必自己重新实现它……有关如何在 ASP.NET MVC 应用程序中使用它的一些示例,您可以在此处找到。

