Как получить дополнительную информацию о пользователе из Azure Mobile/App Services?

Мне нужно получить дополнительную информацию о пользователе из учетных записей социальных сетей, таких как Facebook и Google+. Когда я впервые прочитал о мобильных службах Azure, я подумал, что это святой Грааль социальной аутентификации. Что ж, после целой недели выдергивания волос я начинаю пересматривать свое первое впечатление. Он аутентифицируется настолько легко, насколько это возможно. Я настроил Google+ и FB для работы с Azure, настроил Azure на использование ключа/секрета от каждого провайдера, и все просто заработало. Я смог войти в систему отлично. Проблема началась, когда я попытался получить информацию от вошедшего в систему пользователя, что, честно говоря, я считаю базовым!

Мобильные службы Azure возвращают идентификатор пользователя и токен, которые нельзя использовать для запроса дополнительной информации о выбранном поставщике. Так что даже если бы я создал второй запрос, используя, например, API графа FB, это не сработало бы (я пробовал!). Этот токен является собственным токеном Azure. Итак, из нескольких сообщений Карлоса Фигейры (SE в Azure) я узнал, что мне нужно настроить свой сценарий Azure, сделать запрос в Azure, и тогда я смогу заставить его работать.

Я также прочитал несколько сообщений от Карлоса Фигейры о том, как реализовать эту дополнительную функциональность, и хотя это было не то, что я искал (настройка сервера), я решил работать с этим. Но мой возвращаемый тип — MobileServiceUser, и этот тип имеет только 2 свойства: UserId и MobileServiceAuthenticationToken. Поэтому даже после добавления сценария сервера от Карлоса я не смог получить дополнительную информацию из своего приложения Xamarin.

Я много читал, много исследовал и не мог найти ответа =/ Кстати, это не ответ: Как получить имя пользователя, адрес электронной почты и т. д. от MobileServiceUser?

Кому-нибудь удалось заставить его работать?

PS: я не публикую здесь код, потому что он работает. Если вы думаете, что проверка какой-то части моего кода поможет решить проблему, просто дайте мне знать.

Заранее спасибо!

РЕДАКТИРОВАТЬ:

Скрипт

function insert(item, user, request) {
    item.UserName = "<unknown>"; // default
    user.getIdentities({
        success: function (identities) {
            var url = null;
            var oauth = null;
            if (identities.google) {
                var googleAccessToken = identities.google.accessToken;
                url = 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' + googleAccessToken;
            } else if (identities.facebook) {
                var fbAccessToken = identities.facebook.accessToken;
                url = 'https://graph.facebook.com/me?access_token=' + fbAccessToken;
            } else if (identities.microsoft) {
                var liveAccessToken = identities.microsoft.accessToken;
                url = 'https://apis.live.net/v5.0/me/?method=GET&access_token=' + liveAccessToken;
            } else if (identities.twitter) {
                var userId = user.userId;
                var twitterId = userId.substring(userId.indexOf(':') + 1);
                url = 'https://api.twitter.com/1.1/users/show.json?user_id=' + twitterId;
                var consumerKey = process.env.MS_TwitterConsumerKey;
                var consumerSecret = process.env.MS_TwitterConsumerSecret;
                oauth = {
                    consumer_key: consumerKey,
                    consumer_secret: consumerSecret,
                    token: identities.twitter.accessToken,
                    token_secret: identities.twitter.accessTokenSecret
                };
            }

            if (url) {
                var requestCallback = function (err, resp, body) {
                    if (err || resp.statusCode !== 200) {
                        console.error('Error sending data to the provider: ', err);
                        request.respond(statusCodes.INTERNAL_SERVER_ERROR, body);
                    } else {
                        try {
                            var userData = JSON.parse(body);
                            item.UserName = userData.name;
                            request.execute();
                        } catch (ex) {
                            console.error('Error parsing response from the provider API: ', ex);
                            request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex);
                        }
                    }
                }
                var req = require('request');
                var reqOptions = {
                    uri: url,
                    headers: { Accept: "application/json" }
                };
                if (oauth) {
                    reqOptions.oauth = oauth;
                }
                req(reqOptions, requestCallback);
            } else {
                // Insert with default user name
                request.execute();
            }
        }
    });
}

person eestein    schedule 03.07.2015    source источник


Ответы (2)


Вы правильно говорите о токене на стороне клиента? Этот токен специфичен только для клиента. Если вы используете поток на стороне сервера, этот токен — единственный сервер. Если вы хотите отправить это клиенту, вам нужно сделать это через созданный вами собственный API.

Этот класс, о котором вы говорите, содержит только те два свойства. Но на стороне вашего сервера ваш ServiceUser может получить доступ к различным токенам поставщика удостоверений, чтобы общаться с API этих серверов. Ваш связанный пост верен в том, как вы получаете доступ к токену, вы ошибаетесь в том, где вы можете получить доступ к этому токену, это только на стороне сервера (если вы используете поток входа в систему, направленный на сервер).

person Chris Anderson-MSFT    schedule 04.07.2015
comment
Я думаю, вы что-то неправильно поняли... В вашем связанном сообщении указан правильный способ доступа к токену Я знаю, поэтому я сказал By the way this is not the answer. вы ошиблись в том, где вы можете получить доступ к этому токену, он только на стороне сервера Я знаю, поэтому я сказал So even if I were to create a second request using FB's graph API for instance, that wouldn't work (I've tried!). That token is Azure's own token. Даже если я использую процесс входа на сервер (о котором я сказал в своем посте, у меня есть), я все равно не могу получить эту информацию, потому что класс (да, тот, который вы связали) не позволяет мне. Спасибо за ваше время. - person eestein; 04.07.2015
comment
Таким образом, сервер имеет фактический токен IDP. Таким образом, на стороне сервера вы можете использовать идентификатор ServiceUser, чтобы получить правильный токен для доступа к API IDP. Вот еще один пример, когда они немного запутались в этом и разобрались. stackoverflow .com/questions/25463125/ Класс, который я связал, и класс, из которого вы пытались получить токен, НЕ имеют токена IDP, он имеет только идентификатор MobileService. Скорее всего, вы захотите просто получить данные на стороне сервера, используя метод из связанных постов. - person Chris Anderson-MSFT; 04.07.2015
comment
Хорошо, я пытался сказать вам, что знаю, и я пробовал это. Не сказать, что я сделал это правильно, но я пытался это сделать. Кроме того, мой бэкэнд - это JS, а не .NET, поэтому я не знаю, будет ли решение таким же, не так ли? Поскольку вы работаете с @MS, вы, вероятно, знакомы с Карлосом Фигейрой... как я сказал в своем посте, я следил за его учебными пособиями по бэкенду JS, но опять же, не говорю, что ошибка не с моей стороны... просто говорю, что это не так. Не похоже, что информацию для этого текущего сценария легко получить. Если бы вы могли предоставить дополнительную информацию об этом, я был бы признателен. - person eestein; 04.07.2015
comment
Да, то же самое понятие для бэкэнда JS. Не могли бы вы поделиться своим внутренним кодом, где вы пытаетесь получить доступ к токену IDP пользователя? Я могу попробовать на глаз, если что-то выглядит неправильно. - person Chris Anderson-MSFT; 04.07.2015
comment
Конечно, просто проверьте мой обновленный вопрос. Но, как я уже сказал, проблема в том, что даже если мне удастся вернуть эту информацию, класс MobileServiceUser не позволит мне увидеть эти свойства, потому что у него всего два свойства. Спасибо. - person eestein; 04.07.2015
comment
Да. Так будет всегда. Вам нужен клиентский API или таблица, как предлагает Карлос в конце своего блога, которая возвращает вам эту информацию. MobileServiceUser никогда не будет раскрывать эту информацию напрямую. Вы должны разоблачить это сами. - person Chris Anderson-MSFT; 04.07.2015
comment
Хорошо, после того кода, который я показал вам, что еще мне нужно сделать? Спасибо. - person eestein; 04.07.2015
comment
Используйте последний раздел блога Карлоса. blogs.msdn.com/b/carlosfigueira/archive/2012/10/25/ По сути, вы создаете таблицу идентификаторов, которая синхронизируется с вашим устройством. - person Chris Anderson-MSFT; 04.07.2015
comment
Крис, я ценю ваше время, и, поскольку кажется, что сейчас нет лучшего решения/ответа, я решаю, буду ли я выполнять эту чрезмерную дополнительную работу или просто перейду к обычной реализации oAuth. Я все еще думаю, что вы, ребята, должны были реализовать это по умолчанию! Я понимаю проблемы безопасности, связанные с транзакциями с использованием токена доступа, но получить эту информацию не должно быть так сложно. Спасибо еще раз. - person eestein; 05.07.2015
comment
Спасибо за ответ. Мы работаем над тем, чтобы сделать аутентификацию лучше для нашей следующей итерации. Похоже, что аутентификация на стороне клиента может быть больше, чем вы ожидаете, поскольку вам нужен токен на стороне клиента. Я бы посоветовал взглянуть на это, если вы не хотите создавать API на стороне сервера для получения идентификаторов. Дайте мне знать, если у вас возникнут другие проблемы: [email protected] - person Chris Anderson-MSFT; 05.07.2015
comment
Крис, я бы не хотел и не нуждался в токене, если бы решение Azure принимало запрос области, такой как эти переменные области видимости MS_***, и возвращало эти данные клиенту, например, по электронной почте. Я думаю, что это довольно простая информация для предоставления, даже если это было сделано по запросу, как я уже упоминал, создав переменные MS_*** в Azure. Вы действительно должны подумать об этом, если это не входит в ваши текущие планы. Необходимость очевидна, просто проверьте всех этих коллег-разработчиков, которые спрашивают, как получить эту информацию из лазури... Спасибо. - person eestein; 06.07.2015
comment
К сожалению, при переходе от мобильной службы Azure к мобильным приложениям Azure все немного изменилось. У меня был сценарий, похожий на оригинальный, опубликованный в этой теме, который работал с мобильными службами, чтобы получить профиль пользователя для каждого метода аутентификации. Этот процесс аналогичен мобильным приложениям Azure в том смысле, что вы выполняете аутентификацию через Google, Twitter и т. д. на стороне клиента, а затем вызываете пользовательский API в мобильном приложении, чтобы выполнить получение фактической информации о профиле. Однако в документации отсутствуют некоторые переменные среды. - person James Quick; 03.02.2016
comment
Идите вперед и создайте вопрос, если что-то непонятно в мобильных приложениях. Наша команда следит за вопросами, и мы сделаем все возможное, чтобы помочь. - person Chris Anderson-MSFT; 05.02.2016

Вот пользовательский сценарий API, который я использовал для работы с мобильными службами, чтобы вернуть профиль вошедшего в систему пользователя. Я работаю над обновлением до мобильных приложений, так как некоторые переменные среды изменились. Хотелось бы узнать, удалось ли кому-нибудь заставить его работать с мобильными приложениями.

exports.get = function (request, response) {
var user = request.user;
user.getIdentities({
    success: function (identities) {
        var req = require('request');
        var url = null;
        var oauth = null;
        var userId = user.userId.split(':')[1];
        console.log('Identities: ', identities);
        if (identities.facebook) {
            url = 'https://graph.facebook.com/me?access_token=' +
                identities.facebook.accessToken;
        } else if (identities.google) {
            url = 'https://www.googleapis.com/oauth2/v3/userinfo' +
                '?access_token=' + identities.google.accessToken;
        } else if (identities.microsoft) {
            url = 'https://apis.live.net/v5.0/me?access_token=' +
                identities.microsoft.accessToken;
        } else if (identities.twitter) {
            var consumerKey = process.env.MS_TwitterConsumerKey;
            var consumerSecret = process.env.MS_TwitterConsumerSecret;
            oauth = {
                consumer_key: consumerKey,
                consumer_secret: consumerSecret,
                token: identities.twitter.accessToken,
                token_secret: identities.twitter.accessTokenSecret
            };
            url = 'https://api.twitter.com/1.1/users/show.json?' +
                'user_id=' + userId + '&include_entities=false';
        } else {
            response.send(500, { error: 'No known identities' });
            return;
        }

        if (url) {
            var reqParams = { uri: url, headers: { Accept: 'application/json' } };
            if (oauth) {
                reqParams.oauth = oauth;
            }
            req.get(reqParams, function (err, resp, body) {
                if (err) {
                    console.error('Error calling provider: ', err);
                    response.send(500, { error: 'Error calling provider' });
                    return;
                }

                if (resp.statusCode !== 200) {
                    console.error('Provider call did not return success: ', resp.statusCode);
                    response.send(500, { error: 'Provider call did not return success: ' + resp.statusCode });
                    return;
                }

                try {
                    var userData = JSON.parse(body);
                    response.send(200, userData);
                } catch (ex) {
                    console.error('Error parsing response: ', ex);
                    response.send(500, { error: ex });
                }
            });
        } else {
            response.send(500, { error: 'Not implemented yet', env: process.env });
        }
    }
});

};

person James Quick    schedule 03.02.2016
comment
Итак, идентификатор пользователя Azure включает токен доступа поставщика (facebook), правильно ли это? - person Emil; 10.11.2017