web-dev-qa-db-ja.com

ASP.NET MVC 5とOWINを使用してFacebookの姓名を取得する方法

「名前」フィールドが提供されていることは知っていますが、姓と名に明示的にアクセスしたいと思います。誰かがこれを手伝ってくれる?私はまだASP.Net MVCに頭を抱えています。

20
David Poxon

Startup.Auth.cs ConfigureAuth(IAppBuilder app)メソッドで、Facebookに次のように設定します。

var x = new FacebookAuthenticationOptions();
        x.Scope.Add("email");
        x.AppId = "*";
        x.AppSecret = "**";
        x.Provider = new FacebookAuthenticationProvider()
        {
            OnAuthenticated = async 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"));

                    }

                }
        };

        x.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
        app.UseFacebookAuthentication(x);
        /*
        app.UseFacebookAuthentication(
           appId: "*",
           appSecret: "*");
         * */

次に、これを使用してユーザーのログイン情報にアクセスします。

var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();

そして、次のように名を取得します。

var firstNameClaim = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:first_name");
46
David Poxon

Facebookは許可APIを変更しました。詳細については、こちらをご覧ください: https://developers.facebook.com/docs/facebook-login/permissions

名前にはpublic_profile権限が必要です

var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
    AppId = "appId",
    AppSecret = "key"
};
facebookAuthenticationOptions.Scope.Add("email");
facebookAuthenticationOptions.Scope.Add("public_profile");
app.UseFacebookAuthentication(facebookAuthenticationOptions);

そしてあなたはそれを使ってそれを得ることができます:

var loginInfo = await authenticationManager.GetExternalLoginInfoAsync();
loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:name")

authenticationManagerはインスタンスです。次を使用して取得できます。

HttpContext.GetOwinContext().Authentication;
7

残念ながら、FacebookはAPIアップデート2.4でデフォルトの戻り値を変更したため、このメソッドは機能しなくなりました。

First_nameなどを取得する唯一の方法のようですが、今はFacebook Graph APIを使用することです( この投稿のように )。

私はまた、この問題に対処するKatanaプロジェクトサイトで this post を見つけて、すでにプルリクエストを送信しましたが、Jetはマージされていません。

うまくいけば、これは誰かを少し時間を安全にします;)

6
Anton

2017年現在、これは私のために機能しているコードです(上記のDavid Poxonのコードに感謝します)。 Microsoft.Owin.Security.Facebookのバージョン3.1.0にアップグレードしたことを確認してください。

Startup.Auth.cs(または場合によってはStartup.cs)に、次のコードを配置します。

app.UseFacebookAuthentication(new FacebookAuthenticationOptions()
{
    AppId = "***",
    AppSecret = "****",
    BackchannelHttpHandler = new HttpClientHandler(),
    UserInformationEndpoint = "https://graph.facebook.com/v2.8/me?fields=id,name,email,first_name,last_name",
    Scope = { "email" },
    Provider = new FacebookAuthenticationProvider()
    {
        OnAuthenticated = async 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"));
            }
        }
    }
});

次に、コントローラーの外部ログインコールバックメソッドで、次のコードを追加します。

var firstName = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:first_name").Value;

同様に姓を取得するには、上記の行を使用してurn:facebook:first_nameurn:facebook:last_nameに置き換えます

4
Waqas Shah

2019年1月の時点で、これを確認し、追加のビットをいくつか提供したいと思っていました(答えが書かれた年によっては、競合する情報がたくさんあります!)。 DavidとWaqasが最良の答えです(IMO)。 MVC5、AspNetIdentity 2、IdentityServer 3を使用しています。

まず、FacebookのIDプロバイダー構成:

        app.UseFacebookAuthentication(new FacebookAuthenticationOptions
        {
            AuthenticationType = "facebook",
            Caption = "Login with Facebook",
            SignInAsAuthenticationType = signInAsType,

            AppId = ConfigurationManager.AppSettings["FacebookAppId"],
            AppSecret = ConfigurationManager.AppSettings["FacebookAppSecret"],

            Provider = new FacebookAuthenticationProvider()
            {
                OnAuthenticated = ctx =>
                {
                    foreach (var claim in ctx.User)
                    {
                        var claimType = $"urn:facebook:{claim.Key}";
                        var claimValue = claim.Value.ToString();
                        if (!ctx.Identity.HasClaim(claim.Key, claimValue))
                        {
                            ctx.Identity.AddClaim(new Claim(claim.Key, claimValue));
                        }
                    }
                    return Task.FromResult(0);
                }
            }
        });

他の回答の一部とは異なり、これは追加の要求されたフィールドをデフォルトで取得するフィールドと組み合わせ、urn:facebook:をクレームの先頭から削除して、デフォルトのクレーム命名スキームと一致させます。

ScopesFieldsを追加する必要はありません(少なくとも、姓名は除く)。 Microsoft.Owin.Security.Facebookのバージョン4.1では、これがすでに行われています。 FacebookAuthenticationOptionsのソースコードはこちら です。関連ビット:

    public FacebookAuthenticationOptions()
        : base(Constants.DefaultAuthenticationType)
    {
        Caption = Constants.DefaultAuthenticationType;
        CallbackPath = new PathString("/signin-facebook");
        AuthenticationMode = AuthenticationMode.Passive;
        Scope = new List<string>();
        BackchannelTimeout = TimeSpan.FromSeconds(60);
        SendAppSecretProof = true;
        _fields = new HashSet<string>();
        CookieManager = new CookieManager();

        AuthorizationEndpoint = Constants.AuthorizationEndpoint;
        TokenEndpoint = Constants.TokenEndpoint;
        UserInformationEndpoint = Constants.UserInformationEndpoint;

        Scope.Add("public_profile");
        Scope.Add("email");
        Fields.Add("name");
        Fields.Add("email");
        Fields.Add("first_name");
        Fields.Add("last_name");
    }

(私と同じように)IdentityServer 3を使用している場合は、次のようにカスタムUserServiceで認証に関するこれらの要求を取得する必要があります。

    public async override Task AuthenticateExternalAsync(ExternalAuthenticationContext ctx)
    {
        // first, lets see if we have enough data from this external provider
        // at a minimum, FirstName, LastName, and Email are required

        string email = null;
        string firstName = null;
        string lastName = null;

        var idp = ctx.ExternalIdentity.Provider;

        email = GetClaimValue(ctx, "email");

        if (idp == "google")
        {
            firstName = GetClaimValue(ctx, "given_name");
            lastName = GetClaimValue(ctx, "family_name");
        }
        else if (idp == "facebook")
        {
            firstName = GetClaimValue(ctx, "first_name");
            lastName = GetClaimValue(ctx, "last_name");
        }

        var missingClaims = "";
        if (email == null)
        {
            missingClaims = "email";
        }
        if (firstName == null)
        {
            if (missingClaims.Length > 0) { missingClaims += ", "; }
            missingClaims += "first name";
        }
        if (lastName == null)
        {
            if (missingClaims.Length > 0) { missingClaims += ", "; }
            missingClaims += "last name";
        }

        if (missingClaims.Length > 0)
        {
            var errorMessage = $"The external login provider didn't provide the minimum required user profile data.  Missing: {missingClaims}  " +
                "Verify that these fields are specified in your external login provider user profile and that you have allowed external apps (i.e. this one) access to them.  " +
                "Alternatively, you can try a different external login provider, or create a local acount right here.";
            ctx.AuthenticateResult = new AuthenticateResult(errorMessage);
            return;
        }

        var login = new Microsoft.AspNet.Identity.UserLoginInfo(ctx.ExternalIdentity.Provider, ctx.ExternalIdentity.ProviderId);
        var user = await _userManager.FindAsync(login);
        if (user == null)
        {
            // this user either does not exist or has not logged in with this identity provider
            // let's see if they already exist (by checking to see if there is a user account with this email address)

            user = await _userManager.FindByEmailAsync(email);
            if (user == null)
            {
                // there is no existing user with this email, therefore, a new user will be created
                user = new MotoTallyUser()
                {
                    Id = Guid.NewGuid(),
                    UserName = email,
                    Email = email,
                    EmailConfirmed = true,
                    FirstName = firstName,
                    LastName = lastName
                };
                await _userManager.CreateAsync(user);
                await _userManager.AddLoginAsync(user.Id, login);
            }
            else
            {
                // this user DOES exist (matched email provided by external login provider)
                // however, they have not logged in with this identity provider
                // therefore, update the user info with that reported by the external identity provider, and add the external login

                user.UserName = email;
                user.Email = email;
                user.EmailConfirmed = true;
                user.FirstName = firstName;
                user.LastName = lastName;
                await _userManager.UpdateAsync(user);
                await _userManager.AddLoginAsync(user.Id, login);
            }
        }
        else
        {
            // this user DOES exist (they already have an external login on record)
            // therefore, update the user info with that reported by the external identity provider (no need to add external login, its already there)

            user.UserName = email;
            user.Email = email;
            user.EmailConfirmed = true;
            user.FirstName = firstName;
            user.LastName = lastName;
            await _userManager.UpdateAsync(user);
        }

        ctx.AuthenticateResult = new AuthenticateResult(user.Id.ToString(), user.Email, null, ctx.ExternalIdentity.Provider);
        return;
    }

    private string GetClaimValue(ExternalAuthenticationContext ctx, string claimType)
    {
        if (ctx.ExternalIdentity.Claims.FirstOrDefault(x => x.Type == claimType) != null)
        {
            return ctx.ExternalIdentity.Claims.FirstOrDefault(x => x.Type == claimType).Value;
        }
        return null;
    }

これが誰かを助けることを願っています!

1
Scuzzlebutt
 private Uri RedirectUri
        {
            get
            {
                var uriBuilder = new UriBuilder(Request.Url);
                uriBuilder.Query = null;
                uriBuilder.Fragment = null;
                uriBuilder.Path = Url.Action("FacebookCallback");
                return uriBuilder.Uri;
            }
    }

    [AllowAnonymous]
    public ActionResult Facebook()
    {
        var fb = new FacebookClient();
        var loginUrl = fb.GetLoginUrl(new
        {
            client_id = "296002327404***",
            client_secret = "4614cd636ed2029436f75c77961a8***",
            redirect_uri = RedirectUri.AbsoluteUri,
            response_type = "code",
            scope = "email" // Add other permissions as needed
        });

        return Redirect(loginUrl.AbsoluteUri);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult LogOff()
    {
        FormsAuthentication.SignOut();
        return View("Login");
    }
    public ActionResult FacebookCallback(string code)
    {
        var fb = new FacebookClient();
        dynamic result = fb.Post("oauth/access_token", new
        {
            client_id = "296002327404***",
            client_secret = "4614cd636ed2029436f75c77961a8***",
            redirect_uri = RedirectUri.AbsoluteUri,
            code = code
        });

        var accessToken = result.access_token;

        // Store the access token in the session for farther use
        Session["AccessToken"] = accessToken;

        // update the facebook client with the access token so 
        // we can make requests on behalf of the user
        fb.AccessToken = accessToken;

        // Get the user's information
        dynamic me = fb.Get("me?fields=first_name,middle_name,last_name,id,email");
        string email = me.email;
        string firstname = me.first_name;
        string middlename = me.middle_name;
        string lastname = me.last_name;

        db.Insert_customer(firstname,email,null,null,null,null,null,null,null,null,null,null,1,1,System.DateTime.Now,1,System.DateTime.Now);

        // Set the auth cookie
        FormsAuthentication.SetAuthCookie(email, false);
        return RedirectToAction("Index", "Home");
    }

}
}
1
sanket parikh

Facebookは、アップグレード2.4でGraph APIが値を返す方法を変更しました。ここで、取得したいすべてのフィールドを明示的に指定する必要があります。

次のメモを参照してください 開発者向けアップグレードアップグレード情報

バージョン2.4でのグラフAPIの変更

これまで、Graph API呼び出しからの応答は一連のデフォルトフィールドを返していました。ペイロードサイズを削減し、モバイルネットワークの遅延を改善するために、ほとんどのGraph API呼び出しで返されるデフォルトフィールドの数を減らしました。 v2.4では、呼び出しの応答フィールドを宣言的にリストする必要があります。

facebookからメール、FirstName、LastNameを取得するには:

まず、インストールする必要があります Facebook SDK for .NET nugetパッケージ

次に、startup.Auth.csで、Facebook認証の設定を次のように変更します。

     app.UseFacebookAuthentication(new FacebookAuthenticationOptions
        {
            // put your AppId and AppSecret here. I am reading them from AppSettings 
            AppId = ConfigurationManager.AppSettings["FacebookAppId"],
            AppSecret = ConfigurationManager.AppSettings["FacebookAppSecret"],
            Scope = { "email" },
            Provider = new FacebookAuthenticationProvider
            {
                OnAuthenticated = context =>
                {
                    context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
                    return Task.FromResult(true);
                }
            }
        });

        // this is no longer needed
        //app.UseFacebookAuthentication(
        //   appId: ConfigurationManager.AppSettings["FacebookAppId"],
        //   appSecret: ConfigurationManager.AppSettings["FacebookAppSecret"]);

最後に、AccountControllerで、ExternalLoginCallbackメソッドに次のコードを追加します。

if (string.Equals(loginInfo.Login.LoginProvider, "facebook", StringComparison.CurrentCultureIgnoreCase))
        {
            var identity = AuthenticationManager.GetExternalIdentity(DefaultAuthenticationTypes.ExternalCookie);
            var access_token = identity.FindFirstValue("FacebookAccessToken");
            var fb = new FacebookClient(access_token);

            // you need to specify all the fields that you want to get back
            dynamic myInfo = fb.Get("/me?fields=email,first_name,last_name"); 
            string email = myInfo.email;
            string firstName = myInfo.first_name;
            string lastName = myInfo.last_name;
        }

取得できるその他のパラメーターについては、 facebook API Guid を参照してください。

0
Hooman Bahreini