私は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プロファイルからそのメールアドレスを取得したいのですが、このデータは生成されたクレームに含まれないことです。アドレスを取得するために、これらの選択肢について考えている私はそう:
Facebookから取得され、クレームに変換されるデータセットに電子メールアドレスを含めるようにASP.NET Identityエンジンに指示します。これがすべてで可能であるならば、私は知りません。
FacebookグラフAPI( https://developers.facebook.com/docs/getting-started/graphapi )を使用して、FacebookユーザーID(クレームデータに含まれる)を使用してメールアドレスを取得します。 )。ユーザーがプライベートとして彼の電子メールアドレスを設定している場合しかし、これは動作しません。
FacebookグラフAPIを使用しますが、FacebookユーザーIDの代わりに「me」を指定します( https://developers.facebook.com/docs/reference/api/user )。しかし、アクセストークンが必要であり、ASP.NETがユーザーデータを取得するために使用するアクセストークンを取得する方法(または可能かどうか)がわかりません。
そこで質問です:
どのように私はFacebookのから追加情報を取得するために、ASP.NETアイデンティティエンジンに指示し、請求データに含めることができますか?
または代わりに、どのように私はFacebookの自分自身に尋ねることができるように、トークン生成されたアクセスを取得することができますか?
ありがとうございました!
注:認証システムの場合、アプリケーションは、これにリンクされているサンプルプロジェクトに基づくコードを使用しますSO answer: https://stackoverflow.com/a/18423474/4574
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が送信した場合、電子メールが既に取得され、クレームとしてここに追加されていることを確認します。見えないの?
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
そして、フィードバック、修正、または改善を歓迎します。
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;
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_token
でcontext.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");
ここにあなたを助けるいくつかのステップがあります。ブログ投稿を作成中ですが、しばらく時間がかかります...-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/>");
}