c# - studio - web api ejemplo
¿Por qué el nuevo fb api 2.4 devuelve correo electrónico nulo en MVC 5 con Identity y oauth 2? (6)
Lea el changelog , esto es por diseño. Debe solicitar explícitamente los campos y bordes que desea volver a ajustar en la respuesta:
Campos declarativos Para tratar de mejorar el rendimiento en redes móviles, los nodos y bordes en v2.4 requieren que solicite explícitamente los campos que necesita para sus solicitudes
GET
. Por ejemplo,GET /v2.4/me/feed
ya no incluye me gusta y comentarios de forma predeterminada, peroGET /v2.4/me/feed?fields=comments,likes
devolverá los datos. Para obtener más detalles, consulte los docs sobre cómo solicitar campos específicos.
Todo solía funcionar perfectamente hasta que fb actualizó su api a 2.4 (tenía 2.3 en mi proyecto anterior).
Hoy, cuando agrego una nueva aplicación en desarrolladores de fb, la obtengo con api 2.4.
El problema: ahora recibo un correo electrónico nulo de fb (
loginInfo.email = null
).
Por supuesto, verifiqué que el correo electrónico del usuario está en estado público en el perfil de fb,
y
loginInfo
objeto
loginInfo
pero no encontré ninguna otra dirección de correo electrónico.
y lo busqué en Google pero no encontré ninguna respuesta.
por favor cualquier ayuda ... estoy un poco perdido ...
Gracias,
Mi código original (que funcionó en 2.3 api):
En AccountController.cs:
//
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
//A way to get fb details about the log-in user:
//var firstNameClaim = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:first_name"); <--worked only on 2.3
//var firstNameClaim = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:name"); <--works on 2.4 api
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email }); //<---DOESN''T WORK. loginInfo.Email IS NULL
}
}
En el Startup.Auth.cs:
Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions fbOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
{
AppId = System.Configuration.ConfigurationManager.AppSettings.Get("FacebookAppId"),
AppSecret = System.Configuration.ConfigurationManager.AppSettings.Get("FacebookAppSecret"),
};
fbOptions.Scope.Add("email");
fbOptions.Provider = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationProvider()
{
OnAuthenticated = (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"));
}
return System.Threading.Tasks.Task.FromResult(0);
}
};
fbOptions.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
app.UseFacebookAuthentication(fbOptions);
Para mí, este problema se resolvió actualizando a
Microsoft.Owin.Security.Facebook 3.1.0
y agregando ''correo electrónico'' a la colección
Fields
:
var options = new FacebookAuthenticationOptions
{
AppId = "-------",
AppSecret = "------",
};
options.Scope.Add("public_profile");
options.Scope.Add("email");
//add this for facebook to actually return the email and name
options.Fields.Add("email");
options.Fields.Add("name");
app.UseFacebookAuthentication(options);
Para resolver esto, necesita instalar el SDK de Facebook desde los paquetes NuGet.
En el archivo de inicio
app.UseFacebookAuthentication(new FacebookAuthenticationOptions
{
AppId = "XXXXXXXXXX",
AppSecret = "XXXXXXXXXX",
Scope = { "email" },
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = context =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
return Task.FromResult(true);
}
}
});
En controlador o ayudante
var identity = AuthenticationManager.GetExternalIdentity(DefaultAuthenticationTypes.ExternalCookie);
var accessToken = identity.FindFirstValue("FacebookAccessToken");
var fb = new FacebookClient(accessToken);
dynamic myInfo = fb.Get("/me?fields=email,first_name,last_name,gender"); // specify the email field
Con esto puede obtener el EmailId, nombre, apellido, género.
También puede agregar sus propiedades adicionales requeridas en esa cadena de consulta.
Espero que esto ayude a alguien.
Solo quiero agregar a la respuesta de Mike que esta línea
facebookOptions.Scope.Add("email");
todavía necesita ser agregado después
var facebookOptions = new FacebookAuthenticationOptions()
{
AppId = "*",
AppSecret = "*",
BackchannelHttpHandler = new FacebookBackChannelHandler(),
UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=id,name,email,first_name,last_name,location"
}
Y si ya registró su cuenta de Facebook en su sitio web de desarrollo sin "permiso de correo electrónico". Después de cambiar el código y volver a intentarlo, aún no recibirá el correo electrónico porque el permiso de correo electrónico no se otorga a su sitio web de desarrollo. La forma en que lo hago es ir a https://www.facebook.com/settings?tab=applications , eliminar mi aplicación de Facebook y volver a hacer el proceso nuevamente.
Tomado de un hilo de Katana, ideé lo siguiente:
Cambie las
UserInformationEndpoint
FacebookAuthenticationOptions
para incluir
UserInformationEndpoint
y
UserInformationEndpoint
como se ve a continuación.
Asegúrese de incluir los nombres de los campos que desea y necesita para su implementación.
var facebookOptions = new FacebookAuthenticationOptions()
{
AppId = "*",
AppSecret = "*",
BackchannelHttpHandler = new FacebookBackChannelHandler(),
UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=id,name,email,first_name,last_name"
}
Luego, cree un
FacebookBackChannelHandler
personalizado que interceptará las solicitudes a Facebook y reparará la URL con formato incorrecto según sea necesario.
ACTUALIZACIÓN:
FacebookBackChannelHandler
se actualiza según una actualización del 27 de marzo de 2017 a la API de FB.
public class FacebookBackChannelHandler : HttpClientHandler
{
protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
if (!request.RequestUri.AbsolutePath.Contains("/oauth"))
{
request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.Replace("?access_token", "&access_token"));
}
var result = await base.SendAsync(request, cancellationToken);
if (!request.RequestUri.AbsolutePath.Contains("/oauth"))
{
return result;
}
var content = await result.Content.ReadAsStringAsync();
var facebookOauthResponse = JsonConvert.DeserializeObject<FacebookOauthResponse>(content);
var outgoingQueryString = HttpUtility.ParseQueryString(string.Empty);
outgoingQueryString.Add("access_token", facebookOauthResponse.access_token);
outgoingQueryString.Add("expires_in", facebookOauthResponse.expires_in + string.Empty);
outgoingQueryString.Add("token_type", facebookOauthResponse.token_type);
var postdata = outgoingQueryString.ToString();
var modifiedResult = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(postdata)
};
return modifiedResult;
}
}
public class FacebookOauthResponse
{
public string access_token { get; set; }
public string token_type { get; set; }
public int expires_in { get; set; }
}
Una adición útil sería verificar la versión 3.0.1 de la biblioteca y lanzar una excepción si cambia. De esa manera sabrá si alguien actualiza o actualiza el paquete NuGet después de que se haya publicado una solución para este problema.
(Actualizado a la compilación, funciona en C # 5 sin el nuevo nombre de la función)
- Actualice Microsoft.Owin a 3.0.1 (Install-Package Microsoft.Owin.Security.OAuth)
- en Startup.Auth.cs agregue facebookOptions.UserInformationEndpoint = " https://graph.facebook.com/v2.4/me?fields=id,name,email ";