身份服务器3 Facebook登录获取电子邮件
身份验证服务器已实施并运行良好。 谷歌登录正在工作,并返回包括电子邮件在内的多项索赔
Facebook登录正在工作,并且我的应用程序处于活动状态,并在新用户登录时请求电子邮件权限。
问题是我无法从oauth端点获取电子邮件,我似乎无法找到access_token手动请求用户信息。 我所拥有的只是从Facebook登录端点返回的“代码”。
这是IdentityServer设置。
var fb = new FacebookAuthenticationOptions
{
AuthenticationType = "Facebook",
SignInAsAuthenticationType = signInAsType,
AppId = ConfigurationManager.AppSettings["Facebook:AppId"],
AppSecret = ConfigurationManager.AppSettings["Facebook:AppSecret"]
};
fb.Scope.Add("email");
app.UseFacebookAuthentication(fb);
然后,我已经定制了AuthenticateLocalAsync方法,但我收到的声明只包含名称。 没有电子邮件声明
通过挖掘身份服务器的源代码,我意识到有一些声称发生了转变facebook声明的事情,所以我扩展了这个类来调试它,看看它是否剥离了任何声明,事实并非如此。
我也看到了使用fiddler的http调用,并且我只看到以下内容(道歉,因为代码格式在url上不起作用,我尝试将querystring params格式化为他们自己的行,但它没有采用)
(facebook.com)
/ dialog / oauth?response_type = code&client_id = xxx&redirect_uri = https%3A%2F%2Fidentity。[site] .com%2Fid%2Fsignin-facebook&scope = email&state = xxx
(facebook.com)
/login.php?skip_api_login = 1&api_key = xxx&signed_next = 1&next = https%3A%2F%2Fwww.facebook.com%2Fv2.7%2Fdialog%2Foauth%3Fredirect_uri%3Dhttps%253A%252F%252Fidentity。[site]。 COM%252Fid%252Fsignin-的Facebook%26state%3Dxxx%26scope%3Demail%26response_type%3Dcode%26client_id%3Dxxx%26ret%3Dlogin%26logger_id%3Dxxx&cancel_url = HTTPS%3A%2F%2Fidentity。[站点] .COM%2Fid%2Fsignin- Facebook%3Ferror%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%26state%3Dxxx%23_%3D_&display = page&locale = en_US&logger_id = xxx
(facebook.com)
POST / cookie / consent /?pv = 1&dpr = 1 HTTP / 1.1
(facebook.com)
/login.php?login_attempt = 1&next = https%3A%2F%2Fwww.facebook.com%2Fv2.7%2Fdialog%2Foauth%3Fredirect_uri%3Dhttps%253A%252F%252Fidentity。[site] .com%252Fid%252Fsignin- Facebook%26state%3Dxxx%26scope%3Demail%26response_type%3Dcode%26client_id%3Dxxx%26ret%3Dlogin%26logger_id%3Dxxx&lwv = 100
(facebook.com)
/v2.7/dialog/oauth?redirect_uri = https%3A%2F%2Fidentity。[site] .com%2Fid%2Fsignin-facebook&state = xxx&scope = email&response_type = code&client_id = xxx&ret = login&logger_id = xxx&hash = XXX
(身份服务器)
/ id / signin-facebook?code = xxx&state = xxx
我在最后一次调用中看到了代码参数,并认为我可以使用代码从facebook API获取access_token https://developers.facebook.com/docs/facebook-login/manually-build-a-login -流
但是,当我尝试从API获取消息告诉我代码已被使用。
我还尝试将UserInformationEndpoint更改为FacebookAuthenticationOptions,强制它通过将?fields = email附加到默认端点位置的末尾来请求电子邮件,但导致身份服务器吐出错误“登录时出现错误外部提供者。错误消息是:access_denied“。
如果我可以通过response_type = id_token来更改中间件来发送请求,但我可能能够解决这一切,但我无法弄清楚如何执行该操作或如何在首先返回时提取该访问令牌能够使用Facebook C#sdk。
所以我想任何帮助或方向都会很棒。 我花了无数小时研究并试图解决问题。 我需要做的就是通过IdentityServer3获取登录用户的电子邮件地址。 听起来不那么难,但我卡住了。
我终于明白了这一点。 答案与Mitra的评论有关,尽管这些答案似乎都不符合该法案,所以我在这里再提一个。 首先,您需要请求access_token,而不是来自Facebook身份验证端点的代码(授权码)。 要做到这一点,请像这样设置它
var fb = new FacebookAuthenticationOptions
{
AuthenticationType = "Facebook",
SignInAsAuthenticationType = signInAsType,
AppId = ConfigurationManager.AppSettings["Facebook:AppId"],
AppSecret = ConfigurationManager.AppSettings["Facebook:AppSecret"],
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);
}
}
};
fb.Scope.Add("email");
app.UseFacebookAuthentication(fb);
然后,您需要在登录后捕获响应。我正在使用IdentityServer3样本存储库中的以下文件,该文件覆盖(读取,提供功能)以从外部网站登录用户所需的方法。 从这个响应中,我使用C#Facebook SDK和ExternalAuthenticationContext中新返回的access_token声明来请求我需要的字段并将它们添加到声明列表中。 然后我可以使用这些信息来创建/登录用户。
public override async Task AuthenticateExternalAsync(ExternalAuthenticationContext ctx)
{
var externalUser = ctx.ExternalIdentity;
var claimsList = ctx.ExternalIdentity.Claims.ToList();
if (externalUser.Provider == "Facebook")
{
var extraClaims = GetAdditionalFacebookClaims(externalUser.Claims.First(claim => claim.Type == "urn:facebook:access_token"));
claimsList.Add(new Claim("email", extraClaims.First(k => k.Key == "email").Value.ToString()));
claimsList.Add(new Claim("given_name", extraClaims.First(k => k.Key == "first_name").Value.ToString()));
claimsList.Add(new Claim("family_name", extraClaims.First(k => k.Key == "last_name").Value.ToString()));
}
if (externalUser == null)
{
throw new ArgumentNullException("externalUser");
}
var user = await userManager.FindAsync(new Microsoft.AspNet.Identity.UserLoginInfo(externalUser.Provider, externalUser.ProviderId));
if (user == null)
{
ctx.AuthenticateResult = await ProcessNewExternalAccountAsync(externalUser.Provider, externalUser.ProviderId, claimsList);
}
else
{
ctx.AuthenticateResult = await ProcessExistingExternalAccountAsync(user.Id, externalUser.Provider, externalUser.ProviderId, claimsList);
}
}
就是这样! 如果您对简化此过程有任何建议,请告诉我。 我正在修改此代码以执行从FacebookAuthenticationOptions对API的调用,但Events属性显然不再存在。
编辑:GetAdditionalFacebookClaims方法仅仅是一个方法,它在给出访问令牌的情况下创建一个新的FacebookClient,并查询Facebook API以获取您需要的其他用户声明。 例如,我的方法如下所示:
protected static JsonObject GetAdditionalFacebookClaims(Claim accessToken)
{
var fb = new FacebookClient(accessToken.Value);
return fb.Get("me", new {fields = new[] {"email", "first_name", "last_name"}}) as JsonObject;
}
链接地址: http://www.djcxy.com/p/36051.html