Как получить доступ к личной информации Facebook, используя идентификатор ASP.NET(OWIN)?

Я разрабатываю веб-сайт в ASP.NET MVC 5 (в настоящее время использую версию RC1). Сайт будет использовать Facebook для аутентификации пользователей и для получения исходных данных профиля.

Для системы аутентификации я использую новый механизм идентификации ASP.NET на основе OWIN (http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-forms-authentication-in-mvc-5.aspx), поскольку он значительно упрощает процесс аутентификации с внешними поставщиками.

Проблема заключается в том, что как только пользователь впервые войдет в систему, я хочу получить его адрес электронной почты из профиля Facebook, но эти данные не включены в генерируемые заявки. Поэтому я подумал об этих альтернативах, чтобы получить адрес:

  • Попросите механизм ASP.NET Identity включить адрес электронной почты в набор данных, который извлекается из Facebook, а затем преобразован к претензиям. Я не знаю, возможно ли это вообще.

  • Используйте графический API Facebook (https://developers.facebook.com/docs/getting-started/graphapi) в получить адрес электронной почты, используя идентификатор пользователя Facebook (который является включенными в данные формулы изобретения). Но это не сработает, если пользователь задайте свой адрес электронной почты как закрытый.

  • Используйте графический API Facebook, но указав "я" вместо Идентификатор пользователя Facebook (https://developers.facebook.com/docs/reference/api/user). Но требуется токен доступа, и я не знаю, как (или если это возможно вообще) получить токен доступа, который использует ASP.NET для получить пользовательские данные.

Итак, вопрос:

  • Как я могу настроить механизм идентификации ASP.NET дополнительную информацию из Facebook и включить ее в формулы данные?

  • Или, альтернативно, как я могу получить сгенерированный токен доступа, так что что я могу спросить Facebook сам?

Спасибо!

Примечание: для системы аутентификации мое приложение использует код на основе примера проекта, связанного с этим ответом SO: qaru.site/info/89117/...

Ответ 1

Чтобы получить дополнительную информацию из 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);

В коде здесь я вижу, что письмо уже получено и добавлено в качестве претензии здесь, если facebook отправил. Вы не можете это увидеть?

Ответ 2

Создайте новый объект Microsoft.Owin.Security.Facebook.AuthenticationOptions в Startup.ConfigureAuth(StartupAuth.cs), передав ему FacebookAppId, FacebookAppSecret и новый AuthenticationProvider. Вы будете использовать лямбда-выражение для передачи методу OnAuthenticated некоторого кода для добавления претензий к идентификатору, который содержит значения, которые вы извлекаете из контекста. Идентичность. Это будет включать access_token по умолчанию. Вы должны добавить адрес электронной почты в область действия. Другие свойства пользователя доступны из контекста .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 я извлекаю ClaimsIdentity из AuthenticationManager, используя внешний файл cookie. Затем я добавляю его в идентификатор, созданный с помощью cookie приложения. Я проигнорировал любые претензии, которые начинаются с "... 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, которое отображается на странице /Account/Manage. Я получаю претензии, которые я ранее хранил в AuthenticationManager.User.Claim, а затем передал их в представление.

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

И любые отзывы, исправления или улучшения будут оценены.

Ответ 3

Он работал у меня только с помощью 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;

Ответ 4

Вам нужно создать экземпляр 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 текущего пользователя loggedin.

Чтобы получить доступ к этому значению позже, вам нужно сделать это:

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

Вот несколько шагов, которые помогут вам. Я в процессе написания сообщения в блоге, но это займет некоторое время... - Добавить Области в провайдере 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 С# 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/>");
        }
    

Ответ 6

мои пары центов на все ответы... если вы все еще хотите спросить Facebook самостоятельно, имеет смысл взглянуть на уже существующие Facebook. Он предоставляет некоторые отличные функциональные возможности, которые уже реализованы, поэтому вам не нужно повторно выполнять его самостоятельно... в каком-то примере, как использовать его в приложении ASP.NET MVC, вы можете найти .