Статьи

ColdFusion и OAuth, часть 2 — LinkedIn


Ранее на этой неделе я обсуждал, как
интегрировать ColdFusion и Facebook с помощью OAuth2. Я упомянул, что это было частью набора примеров, которые я сделал для Facebook, LinkedIn и Google. В сегодняшней статье я собираюсь обсудить API-интерфейс LinkedIn.

К счастью, или я должен сказать, очевидно, так как это также протокол OAuth2, код почти такой же. Я буквально взял демо-версию Facebook, скопировал ее и использовал в качестве отправной точки. Как и Facebook, LinkedIn имеет портал для разработчиков ( developer.linkedin.com ), который включает в себя документацию, а также место для регистрации приложений. Это может быть причиной путаницы для некоторых. Вы можете подумать: «Я не создаю приложение, я просто хочу подключиться к LinkedIn», но в целом и Facebook, и LinkedIn рассматривают эти «приложения» как способ определения вашего соединения с вашим сайтом к его собственному. данные.

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

Нажмите на нее, а затем выберите API Keys.

На следующей странице нажмите «Добавить новое приложение». Форма здесь несколько пугающая. LinkedIn действительно мог бы работать лучше, особенно с использованием некоторых значений по умолчанию, так как мне не нужно было бы повторно вводить одни и те же данные каждый раз. Я бы просто занялся обязательными полями. После настройки вы захотите записать свои ключи OAuth. Все, что вас волнует, это ключ API и секретный ключ:

Теперь мы можем перейти к коду. Как и прежде, наш процесс будет одним из следующих: представить ссылку. Пользователи переходят на LinkedIn. Пользователь отправляется обратно с секретными жетонами добра. Мы получили еще один токен. Тогда у нас есть возможность совершать вызовы API. (Напомним, что и это, и предыдущее демо были написаны для ColdFusion 8. Отсюда и компоненты на основе тегов.)

Во-первых, Application.cfc — относительно точное зеркало кода Facebook.

<cfcomponent output="false">

  <cfset this.name = "cfb8linkedin">
	<cfset this.sessionManagement = true>

	<cffunction name="onApplicationStart" output="false">
		<cfset application.linkedin = structNew()>
		<cfset application.linkedin.apikey = "beer">
		<cfset application.linkedin.secretkey = "isreallygood">

	</cffunction>

	<cffunction name="onRequestStart" output="false">
		<cfif isDefined("url.init")>
			<cfset onApplicationStart()>
		</cfif>
	</cffunction>

</cfcomponent>

Далее код index.cfm. Опять же, я представляю ссылку, которую, я предполагаю, мой пользователь нажмет. Это основано на проверке переменной сеанса, которая будет определена, когда пользователь завершит процесс OAuth.

<cfif not isDefined("session.licode")>

  <cfif isDefined("url.startli")>
		<cfset session.state = createUUID()>
		<cfset redirurl = urlEncodedFormat("http://localhost/testingzone/cf8linkedin/redir.cfm")>
		<cfset liURL = "https://www.linkedin.com/uas/oauth2/authorization?response_type=code" & 
		"&client_id=#application.linkedin.apikey#&scope=r_basicprofile%20r_network%20w_messages" &
		"&state=#session.state#&redirect_uri=#redirurl#">
		<cflocation url="#liURL#" addToken="false">

	</cfif>

	<a href="?startli=1">Login with LinkedIn</a>


<cfelse>

	This is a LI user.

	<cfset session.liAPI = createObject("component","linkedin").init(session.liaccesstoken)>

	<cfdump var="#session.liAPI.getMe()#" label="me" expand="false">
	<cfdump var="#session.liAPI.getFriends(count=40)#" label="friends">

</cfif>

Как и прежде, наши ссылки содержат часть наших данных доступа, список разрешений, а также URL-адрес, указывающий, куда пользователь отправляется обратно. Вероятно, единственная интересная вещь здесь — это сфера. Это отражает разрешения и изменит подсказку, которую видит пользователь. Вы хотите изменить это в зависимости от ваших потребностей.

Как только ссылка нажата, пользователь увидит что-то вроде этого:

Теперь давайте посмотрим на redir.cfm. Опять же, это практически идентично коду Facebook, за исключением того, что их результат для токена доступа красиво отформатирован в JSON, а не в виде строки, которую нужно анализировать вручную.

<cfif isDefined("url.code") and url.state is session.state>
  <cfset session.licode = url.code>

	<cfset redirurl = urlEncodedFormat("http://localhost/testingzone/cf8linkedin/redir.cfm")>

	<cfset liAccessTokenURL = "https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code" &
                "&code=#session.licode#&redirect_uri=#redirurl#" & 
                "&client_id=#application.linkedin.apikey#" & 
                "&client_secret=#application.linkedin.secretkey#">
	<cfhttp url="#liAccessTokenURL#">

	<cfif isJSON(cfhttp.filecontent)>
		<cfset res = deserializeJSON(cfhttp.filecontent)>
		<cfset session.liaccesstoken = res.access_token>
		<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>

Если все работает, пользователь отправляется обратно на страницу index.cfm. Если вы помните, я вызвал компонент linkedin, который инициализирован с моим токеном доступа. Я построил три метода для этого ХФУ. Один для получения пользовательских данных, один для друзей и один для отправки сообщений. Чтобы было ясно, их API поддерживает больше, но это все, что хотел мой друг, так что это все, что я построил. Вот этот компонент.

<cfcomponent output="false">

  <cffunction name="init" access="public" returnType="linkedin" output="false">
		<cfargument name="accesstoken" type="string" required="true">
		<cfset variables.accesstoken = arguments.accesstoken>
		<cfreturn this>
	</cffunction>

	<cffunction name="getFriends" access="public" returnType="struct" output="false">
		<cfargument name="start" type="numeric">
		<cfargument name="count" type="numeric">

		<cfset var httpResult = "">
		<cfset var theURL = "https://api.linkedin.com/v1/people/~/connections?oauth2_access_token=#session.liaccesstoken#">

		<cfif structKeyExists(arguments,"start") and isNumeric(arguments.start)>
			<cfset theURL &= "&start=#arguments.start#"> 
		</cfif>
		<cfif structKeyExists(arguments,"count") and isNumeric(arguments.count)>
			<cfset theURL &= "&count=#arguments.count#"> 
		</cfif>

		<cfhttp url="#theURL#" result="httpResult">
			<cfhttpparam type="header" name="x-li-format" value="json">
		</cfhttp>

		<cfreturn deserializeJSON(httpResult.fileContent)>

	</cffunction>

	<cffunction name="getMe" access="public" returnType="struct" output="false">
		<cfset var httpResult = "">

		<cfhttp url="https://api.linkedin.com/v1/people/~?oauth2_access_token=#variables.accesstoken#" result="httpResult">
			<cfhttpparam type="header" name="x-li-format" value="json">
		</cfhttp>
		<cfreturn deserializeJSON(httpResult.fileContent)>

	</cffunction>

	<cffunction name="sendMessage" access="public" returnType="boolean" output="false">
		<cfargument name="recipients" type="any" required="true">
		<cfargument name="subject" type="string" required="true">
		<cfargument name="body" type="string" required="true">

		<cfset var httpResult = "">

		<cfset var x = "">
		<cfset var m = structNew()>

		<cfset var recips = arrayNew(1)>
		<cfif not isArray(recipients)>
			<cfset arrayAppend(recips, recipients)>
		<cfelse>
			<cfset recips = recipients>
		</cfif>

		<cfset m["recipients"] = structNew()>
		<cfset m["recipients"]["values"] = arrayNew(1)>
		<cfloop index="x" from="1" to="#arrayLen(recips)#">
			<cfset m["recipients"]["values"][x] = structNew()>
			<cfset m["recipients"]["values"][x]["person"] = structNew()>
			<cfset m["recipients"]["values"][x]["person"]["_path"] = "/people/#recips[x]#">
		</cfloop>

		<cfset m["subject"] = arguments.subject>
		<cfset m["body"] = arguments.body>

		<cfhttp url="https://api.linkedin.com/v1/people/~/mailbox?oauth2_access_token=#session.liaccesstoken#"
				  method="post" result="httpResult">
			<cfhttpparam type="header" name="x-li-format" value="json">

				  <cfhttpparam type="body" value="#serializeJSON(m)#">
		</cfhttp>

		<cfreturn httpResult.responseHeader["Status_Code"] eq 201>
	</cffunction>

</cfcomponent>

Наслаждаться. Дайте знать, если у вас появятся вопросы. Завтра я напишу третью запись в серии. В этой записи будет рассказано, как аутентифицировать пользователей с помощью Google.