web-dev-qa-db-ja.com

ASP.NETアイデンティティ(OWIN)を使用して、Facebookの個人情報にアクセスするには?

私はASP.NET MVC 5でWebサイトを開発しています(現在はRC1版を使用して)。サイトでは、ユーザー認証のために、初期プロファイルデータを取得するためのFacebookを使用します。

認証システムには、新しいOWINベースのASP.NET Identityエンジンを使用しています( http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-forms-authentication -in-mvc-5.aspx )。これは、外部プロバイダーとの認証プロセスを大幅に簡素化するためです。

問題は、ユーザーが最初にログインしたら、Facebookプロファイルからそのメールアドレスを取得したいのですが、このデータは生成されたクレームに含まれないことです。アドレスを取得するために、これらの選択肢について考えている私はそう:

  1. Facebookから取得され、クレームに変換されるデータセットに電子メールアドレスを含めるようにASP.NET Identityエンジンに指示します。これがすべてで可能であるならば、私は知りません。

  2. FacebookグラフAPI( https://developers.facebook.com/docs/getting-started/graphapi )を使用して、FacebookユーザーID(クレームデータに含まれる)を使用してメールアドレスを取得します。 )。ユーザーがプライベートとして彼の電子メールアドレスを設定している場合しかし、これは動作しません。

  3. FacebookグラフAPIを使用しますが、FacebookユーザーIDの代わりに「me」を指定します( https://developers.facebook.com/docs/reference/api/user )。しかし、アクセストークンが必要であり、ASP.NETがユーザーデータを取得するために使用するアクセストークンを取得する方法(または可能かどうか)がわかりません。

そこで質問です:

  1. どのように私はFacebookのから追加情報を取得するために、ASP.NETアイデンティティエンジンに指示し、請求データに含めることができますか?

  2. または代わりに、どのように私はFacebookの自分自身に尋ねることができるように、トークン生成されたアクセスを取得することができますか?

ありがとうございました!

注:認証システムの場合、アプリケーションは、これにリンクされているサンプルプロジェクトに基づくコードを使用しますSO answer: https://stackoverflow.com/a/18423474/4574

31
Konamiman

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);

コードごとに here 私は、facebookが送信した場合、電子メールが既に取得され、クレームとしてここに追加されていることを確認します。見えないの?

24
Praburaj

Startup.ConfigureAuth(StartupAuth.cs)で新しいMicrosoft.Owin.Security.Facebook.AuthenticationOptionsオブジェクトを作成し、FacebookAppId、FacebookAppSecret、および新しいAuthenticationProviderを渡します。ラムダ式を使用して、OnAuthenticatedメソッドにコードを渡し、context.Identityから抽出した値を含むクレームをIDに追加します。これには、デフォルトでaccess_tokenが含まれます。スコープにemailを追加する必要があります。他のユーザープロパティは、context.Userから使用できます(たとえば、下部のリンクを参照)。

StartUp.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);
}

AccountControllerでは、外部Cookieを使用してAuthenticationManagerからClaimsIdentityを抽出します。次に、アプリケーションCookieを使用して作成されたIDに追加します。 「... schemas.xmlsoap.org/ws/2005/05/identity/claims」で始まる申し立ては無視されたようです。

AccountController.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);
        } 
    }
}

そして最後に、LOCAL AUTHORITYからのものでない値を表示したいと思います。私は /アカウントに表示されますが、/ページ を管理することを部分図_ExternalUserPropertiesListPartialを作成しました。以前に保存したクレームをAuthenticationManager.User.Claimsから取得し、それをビューに渡します。

AccountController.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>();
}

そして、徹底的にするために、ビュー:

_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>
}

作業例と完全なコードはGitHubにあります: https://github.com/johndpalm/IdentityUserPropertiesSample

そして、フィードバック、修正、または改善を歓迎します。

29
John Palmer

Startup.Authでこれでうまくいきました:

var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()        {
    AppId = "*",
    AppSecret = "**"
};
facebookOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookOptions);

そして、メソッドExternalLoginCallbackまたはExternalLoginConfirmationで以下のメールを取得します:

ClaimsIdentity ext = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var email = ext.Claims.First(x => x.Type.Contains("emailaddress")).Value;
22
Julien

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);

上記のコードでは、access_tokencontext.AccessTokenにアクセスし、現在ログインしているユーザーのClaimsに追加しています。

後でこの値にアクセスするには、これを行う必要があります。

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;

このすべてを単純化するために、BaseControllerを作成し、Controllersをすべて継承させることができます。

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;
        }
    }
}

次に、コードのアクセストークンを取得するには、プロパティFacebookAccessTokenにアクセスするだけです。

string accessToken = FacebookAccessToken;

いくつかの他の値を取得することが可能です

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"));

Scopeメールを必要とするメールを取得するために、すべてのフィールドが使用できるわけではないことに注意してください。

facebookOptions.Scope.Add("email");

次に、OnAuthenticatedイベントで次のようにアクセスします。

context.User.Value<string>("email");
5
BrunoLM

ここにあなたを助けるいくつかのステップがあります。ブログ投稿を作成中ですが、しばらく時間がかかります...-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",
        });         
  • アクセストークンを使用して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/>");
        }
    
2
pranav rastogi

すべての答えに私のカップルセント...まだFacebookに自分で尋ねたい場合は、既存の Facebook パッケージを見てみるのが理にかなっています。既に実装されているいくつかの優れた機能を提供するため、自分で再実装する必要はありません... ASP.NET MVCアプリケーション内での使用方法の例 here を見つけることができます。

0
Mr. Pumpkin