WebApi Facebook身份验证,电子邮件地址为

时间:2017-06-06 06:19:31

标签: asp.net-mvc facebook authentication asp.net-web-api oauth-2.0

我想在Facebook上使用他们的电子邮件地址签名我的用户。我已经配置了我的Facebook身份验证:

var facebookAuthenticationOptions = new FacebookAuthenticationOptions
{
    AppId = facebookId,
    AppSecret = facebookSecret,
    Provider = new FacebookProvider()
};
app.UseFacebookAuthentication(facebookAuthenticationOptions);

我已覆盖Facebook提供商也返回电子邮件地址:

public class FacebookProvider : FacebookAuthenticationProvider
{
    public override Task Authenticated(FacebookAuthenticatedContext context)
    {
        var accessTokenClaim = new Claim("ExternalAccessToken", context.AccessToken, "urn:facebook:access_token");
        context.Identity.AddClaim(accessTokenClaim);
        var extraClaims = GetAdditionalFacebookClaims(accessTokenClaim);
        context.Identity.AddClaim(new Claim(ClaimTypes.Email, extraClaims.First(k => k.Key == "email").Value.ToString()));
        context.Identity.AddClaim(new Claim("Provider", context.Identity.AuthenticationType));
        context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirstValue(ClaimTypes.Name)));

        var userDetail = context.User;
        var link = userDetail.Value<string>("link") ?? string.Empty;
        context.Identity.AddClaim(new Claim("link", link));
        context.Identity.AddClaim(new Claim("FacebookId", userDetail.Value<string>("id")));
        return Task.FromResult(0);
    }

    private static JsonObject GetAdditionalFacebookClaims(Claim accessToken)
    {
        var fb = new FacebookClient(accessToken.Value);
        return fb.Get("me", new { fields = new[] { "email" } }) as JsonObject;
    }

在MVC中一切正常 - 在LoginOwinCallback函数中,我能够检索从Facebook返回的用户的电子邮件地址。我试图在WebApi中使用令牌身份验证而不是外部cookie来实现相同的功能。但是,虽然我可以看到我的提供商将电子邮件声明添加到响应中,但是当我在以下例程中调用AuthenticateAsync方法时,不包括电子邮件声明。

private async Task<ExternalLoginInfo> GetExternalLoginInfoAsync()
{
    var result = await Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalBearer);

    if (result == null || result.Identity == null) return null;

    var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
    if (idClaim != null)
    {
        return new ExternalLoginInfo()
        {
            DefaultUserName = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", ""),
            ExternalIdentity = result.Identity,
            Login = new UserLoginInfo(idClaim.Issuer, idClaim.Value)
        };
    }

    return null;
}

任何想法我做错了什么?

1 个答案:

答案 0 :(得分:1)

对于遇到同样问题的其他人,电子邮件声明可用 - 只是有点隐藏。

首先,要从Facebook正确检索用户的电子邮件地址,Startup.Auth.cs的ConfigureAuth方法中的身份验证设置应为:

app.UseFacebookAuthentication(new FacebookAuthenticationOptions
{
    AppId = facebookId,
    AppSecret = facebookSecret,
    Scope= {"email"},
    UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=email"
});

在MVC AccountController类的LoginOwinCallback方法中,电子邮件地址位于var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();返回的ExternalLoginInfo对象的Email属性中。

要在WebAPI AccountController类中检索电子邮件地址,您需要将User.Identity对象强制转换为ClaimsIdentity类型。

[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
{
    if (error != null)
    {
        return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
    }

    if (!User.Identity.IsAuthenticated)
    {
        return new ChallengeResult(provider, this);
    }

    // get all of the claims
    var claimsIdentity = User.Identity as ClaimsIdentity;  // this cast exposes all of the claims returned by Facebook

    // get the external login details
    var externalLogin = ExternalLoginData.FromIdentity(claimsIdentity);

    if (externalLogin == null)
    {
        return InternalServerError();
    }

    if (externalLogin.LoginProvider != provider)
    {
           AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        return new ChallengeResult(provider, this);
    }

    var user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
            externalLogin.ProviderKey));

    var hasRegistered = user != null;

    if (hasRegistered)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

        var oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
            OAuthDefaults.AuthenticationType);
        var cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
            CookieAuthenticationDefaults.AuthenticationType);

        var properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
        AuthenticationManager.SignIn(properties, oAuthIdentity, cookieIdentity);
    }
    else
    {
        var claims = claimsIdentity?.Claims ?? externalLogin.GetClaims();
        var identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
        AuthenticationManager.SignIn(identity);
    }

    return Ok();
}

这意味着您可以使用身份上的FindFirst方法查找Facebook返回的电子邮件声明。