На прошлой неделе по какой-то причине у меня было несколько запросов на пример интеграции ColdFusion и OAuth. В итоге я создал быстрые демоверсии для Facebook, LinkedIn и Google. На этой неделе я буду вести блог по очереди, надеясь, что эти записи помогут другим. Сегодня я собираюсь поделиться кодом Facebook.
Прежде чем начать, я хочу предупредить людей. Я написал этот код очень быстро. Это не оптимизировано. Кроме того, человек, которому я помогал, был на ColdFusion 8. Так что код не совсем то, что я бы назвал в курсе. Конечно, он будет отлично работать с ColdFusion 10. Я обычно предполагаю, что люди берут мои примеры кода здесь как примеры кода, но я хотел быть более ясным, что этот код, вероятно, не будет наилучшей практикой.
Для начала убедитесь, что у вас есть доступ к порталу разработчиков Facebook (developer.facebook.com) и создайте новое приложение.
Вы можете называть это как хотите, но название должно как-то отражать ваш сайт. Пользователи увидят это при запуске вашего приложения, поэтому ознакомьтесь с ним. Вы можете игнорировать два других варианта.
На следующей странице запишите свой идентификатор приложения и секрет приложения:
Нажмите «Веб-сайт с Facebook Login» и введите значение для вашего сайта. Вы можете и, вероятно, должны использовать локальный домен. Другими словами, вы можете ввести что-то под localhost. Очевидно, это изменится на рабочий URL-адрес, как только вы закончите, но для тестирования, localhost подойдет. Для моего тестирования я использовал: http: // localhost / testingzone / cf8fb и нажал «Сохранить изменения».
Вот и все на стороне Facebook. Теперь давайте поговорим о процессе OAuth в целом. Я не буду вдаваться в подробности, так как OAuth уже обсуждался в другом месте, и моя цель здесь — продемонстрировать пример ColdFusion, но на высоком уровне процесс выглядит следующим образом:
- Ваш сайт сообщает пользователю, что вы собираетесь отправить его в Facebook для аутентификации / подключения.
- Вы создаете «специальную» ссылку, которая включает в себя некоторую необходимую ерунду в URL. Наряду с необходимой хренью, у вас будет дополнительная хрень. Так, например, многие провайдеры OAuth просят вас точно указать, что вы хотите использовать от пользователя. Т.е. сколько личных данных вам требуется. Ваша ссылка будет включать это, и Facebook тогда предупредит пользователя. То есть: «Этот сайт хочет взять с вас деньги на обед, прочитать вашу электронную почту и иметь отношения со своими близкими».
- Пользователь нажимает и попадает на Facebook.com со специальным экраном. Смотрите предыдущий пункт о том, как этот экран может измениться.
- Пользователь нажимает «Да» или «Нет» (или одобряет, или что-то еще).
- Facebook отправляет вас обратно на ваш сайт. В URL будет флаг, который вы можете проверить, который сообщит вам, разрешил ли пользователь ваше приложение. Если они сделали, у вас также будет специальный код.
- Вы берете этот код, делаете запрос (используя CFHTTP) в Facebook, чтобы получить токен секретного доступа.
- Этот токен доступа затем позволяет вам получить материал. Что зависит от того, что вы просили (см. Второй пункт).
Вот и все — примерно — и что круто, так это то, что вы увидите такой же (по большей части) процесс и в моих следующих записях в блоге.
Имея это в виду, давайте посмотрим на код. Опять же, я хочу предупредить вас, что это немного грубо. Во-первых, Application.cfc:
<cfcomponent output="false"> <cfset this.name = "cfb8fbG"> <cfset this.sessionManagement = true> <cffunction name="onApplicationStart" output="false"> <cfset application.fbappid = "foo"> <cfset application.fbsecret = "goo"> <cfset application.fbredirecturl = "http://localhost/testingzone/cf8fb/redir.cfm"> </cffunction> <cffunction name="onRequestStart" output="false"> <cfif isDefined("url.init")> <cfset onApplicationStart()> </cfif> </cffunction> </cfcomponent>
Очевидно, что идентификатор приложения и секрет приложения удалены выше. URL перенаправления будет использоваться немного позже. Обратите внимание, что я также включил управление сессиями. Теперь давайте посмотрим на index.cfm.
<cfif not isDefined("session.fbcode")> <cfif isDefined("url.startfb")> <cfset session.state = createUUID()> <cflocation url="https://www.facebook.com/dialog/oauth?client_id=#application.fbappid#&redirect_uri=#application.fbredirecturl#&state=#session.state#&scope=friends_hometown" addtoken="false"> </cfif> <a href="?startfb=1">Login with FB</a> <cfelse> This is a FB user. <cfset session.fbAPI = createObject("component","facebook").init(session.fbaccesstoken)> <cfdump var="#session.fbAPI.getMe()#" label="me" expand="false"> <cfdump var="#session.fbAPI.getFriends()#" label="friends"> </cfif>
Этот шаблон состоит из двух частей. Первая часть запускается, когда вы впервые попадаете на сайт и еще не подключились к Facebook. Я использую простую переменную Session для отслеживания этого. Я предоставляю быструю подсказку и при нажатии отправляю пользователя в Facebook. После размышлений, как я это сделал, было отчасти глупо. Я мог бы просто иметь ссылку в оригинальной HTML-ссылке.
Говоря о ссылке, обратите внимание на части к ней. client_id исходит из настроек нашего приложения. redirect_uri просто сообщает Facebook, куда отправлять пользователя, когда он OK / запрещает соединение. Как я уже сказал, вполне нормально, чтобы это было localhost во время тестирования. Переменная состояния является параметром безопасности. Я использую переменную Session для хранения UUID и обеспечения того, чтобы удаленный сайт (в данном случае Facebook) отправлял обратно то же состояние. Я также мог бы использовать его для других вещей, например, для государства. Представьте, что у меня есть 2 области моего сайта, где вы можете подключиться к Facebook. Я мог бы использовать это как способ сказать: «Я был в продуктах» или «Я был в музыке». Наконец, область действия ссылается на то, что я прошу, с точки зрения конфиденциальности пользователя. Проверьте документы Facebook для получения дополнительной информации о том, что вы можете установить в этом отношении.
Итак, что происходит, когда вы нажимаете? Вот снимок экрана.
Теперь давайте посмотрим на redir.cfm, основной обработчик результата от Facebook.
<cfif isDefined("url.code") and url.state is session.state> <cfset session.fbcode = url.code> <cfhttp url="https://graph.facebook.com/oauth/access_token?client_id=#application.fbappid#&redirect_uri=#urlEncodedFormat(application.fbredirecturl)#&client_secret=#application.fbsecret#&code=#session.fbcode#"> <cfif findNoCase("access_token=", cfhttp.filecontent)> <cfset parts = listToArray(cfhttp.filecontent, "&")> <cfset at = parts[1]> <cfset session.fbaccesstoken = listGetAt(at, 2, "=")> <cflocation url="index.cfm" addtoken="false"> <cfelse> <!--- This is an error case. ---> <cfdump var="#cfhttp#"> </cfif> <cfelseif isDefined("url.error_reason")> <!--- Handle error here. Variables are: url.error_reason and error_description ---> </cfif>
Мы начнем с предположения, что Facebook вернул нам переменную кода в строке запроса. Мы также проверяем переменную состояния, о которой я упоминал ранее. На данный момент нам нужно получить токен доступа от Facebook. Это делается с помощью простого вызова CFHTTP. Обратите внимание, что мы возвращаемся в URI перенаправления. Мы больше не вернемся к redir.cfm, это всего лишь часть системы безопасности.
Если все работает нормально, результатом будет строка, которая выглядит следующим образом:
access_token = AAAX & истекает = 5183804
Вот где приведенный выше код разбора строки вступает в игру. Access_token — это то, что даст нам доступ к данным пользователя.
Если вы вернетесь к примеру кода выше для index.cfm, вы заметите, что у меня есть компонент Facebook, связанный с сеансом пользователя. Я могу передать токен доступа и использовать его для будущих звонков. Я написал этот компонент очень быстро. Он не имеет хорошей обработки ошибок или даже нумерации страниц, но вы можете увидеть пример получения моего профиля, а также моих друзей.
<cfcomponent output="false"> <cffunction name="init" access="public" returnType="facebook" output="false"> <cfargument name="accesstoken" type="string" required="true"> <cfset variables.accesstoken = arguments.accesstoken> <cfreturn this> </cffunction> <cffunction name="getFriends" access="public" returnType="array" output="false"> <cfset var httpResult = ""> <cfset var initialResult = ""> <cfhttp url="https://graph.facebook.com/me/friends?fields=name,hometown&access_token=#variables.accesstoken#" result="httpResult"> <cfset initialResult = deserializeJSON(httpResult.filecontent)> <!--- For now, skipping pagination. ---> <cfreturn initialResult.data> </cffunction> <cffunction name="getMe" access="public" returnType="struct" output="false"> <cfset var httpResult = ""> <cfhttp url="https://graph.facebook.com/me?access_token=#variables.accesstoken#" result="httpResult"> <cfreturn deserializeJSON(httpResult.filecontent)> </cffunction> </cfcomponent>
Я не тратил много времени на их API, но он казался чертовски простым в использовании.
Вы можете задаться вопросом — во время тестирования — как мне отобразить этот экран разрешений? Вы хотите перейти к настройкам конфиденциальности Facebook, а затем управлять приложениями. Это может сбивать с толку, потому что есть еще одна ссылка, которая приводит вас к вашим приложениям в качестве разработчика . Вы хотите убедиться, что вы пришли сюда через настройки конфиденциальности, которые затем помогут вам управлять настройками приложения пользователя . Вот мой:
Видишь мое тестовое приложение там сверху? Если щелкнуть значок удаления (x), вы получите следующее приглашение:
Это звучит так, как будто это может полностью удалить приложение, но, чтобы было ясно, это только для конкретного пользователя . Безопасно подтвердить и протестировать вашу заявку снова.
Во всяком случае, я надеюсь, что это поможет. Я хочу пояснить, что здесь задействовано больше, чем то, что я показал, но я хотел поделиться своим примером приложения в надежде, что другие смогут его использовать.