Доступ к Web-сайтам социальных сетей по протоколу OAuth

Часть 2. Создание клиентского Web-приложения для Twitter, использующего OAuth

Comments

Серия контента:

Этот контент является частью # из серии # статей: Доступ к Web-сайтам социальных сетей по протоколу OAuth

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Доступ к Web-сайтам социальных сетей по протоколу OAuth

Следите за выходом новых статей этой серии.

Приступая к чтению данной статьи, вы должны понимать, что OAuth предоставляет сайту потребителя более корректный способ обращения к защищенным ресурсам пользователя, хранящимся у поставщика сервисов, поскольку благодаря OAuth информация о полномочиях никогда не предоставляется сайтам, отличным от того, на котором они первоначально хранятся. Разработав настольное клиентское приложение для Twitter в первой части данной серии статей, вы можете обновлять свой Twitter-статус после получения приложением MyTtDesktopClient доступа к данным, хранящимся в Twitter. Использовать приложение в следующий раз будет еще удобнее, поскольку маркер доступа может использоваться повторно.

В этой статье демонстрируется, как разработать на базе OAuth клиентское Web-приложение для Twitter. Нашей целью является создание Web-приложения, позволяющего пользователям аутентифицироваться в Twitter по протоколу OAuth и обновлять свой статус. Оно также сможет отображать ленты новостей от друзей. Данное приложение может послужить основой для отличного mashup-сайта.

Разработка Web-клиента для Twitter

Подобно MyTtDesktopClient, данное клиентское Web-приложение для Twitter будет позволять пользователям обновлять свой статус. Более того, оно будет отображать последние статусы пользователей и позволять им удалять их. Web-приложение также позволяет установить URL обратного вызова (callback), по которому Twitter перейдет после успешной аутентификации по OAuth. Это очень полезно для целей разработки, поскольку мы можем направить наш браузер на локальный хост (localhost). Вы также заметите, что аутентификация OAuth немного отличается от аутентификации в разработанном ранее настольном приложении при регистрации этого приложения в качестве приложения Browser.

Регистрация Web-приложения в Twitter – MyTtWebClient

Нам снова необходимо зарегистрировать Web-приложение по адресу http://twitter.com/oauth_clients до того, как можно будет использовать OAuth с Twitter. Либо, при желании, вы можете изменить приложение, которое было зарегистрировано для настольного клиентского приложения. Я собираюсь зарегистрировать новое приложение в Twitter следующим образом:

  • Application Name (название приложения): MyTtWebClient.
  • Description (описание): клиентское Web-приложение для Twitter, использующее OAuth.
  • Application Website (Web-сайт приложения): введите домашнюю страницу вашего приложения.
  • Application Type (тип приложения): Browserмы собираемся разрабатывать Web-приложение.
  • Callback URL (URL обратного вызова): введите URL обратного вызова вашего приложения, localhost не будет работать.
  • Default Access type (тип доступа по умолчанию): Read & Write (чтение и запись) – мы хотим предоставлять пользователям доступ по записи.
  • Use Twitter for login (использовать ли Twitter для регистрации): Yes (да) – мы собираемся использовать Twitter для аутентификации.

Отмечу, что в этот раз тип приложения выбирается как Browser, а не Client (как в первой части). Снова не забудьте указать права доступа Read & Write. Отметьте также флажок Yes, user Twitter for login.

После успешной регистрации вы получите ключ потребителя (consumer key), секретную информацию (consumer secret) и три URL-адреса (URL маркера запроса (request token), URL маркера доступа (access token) и URL авторизации). Ключ потребителя и секретная информация указывается в файле WEB-INF/web.xml.

Разработка и тестирование MyTtWebClient

Если вы надеетесь скомпилировать и запустить Web-приложение без предварительного прочтения кода (исходный код доступен по ссылке, приведенной в разделе Загрузка), нужно установить ваш собственный ключ потребителя и секретную информацию в файле web.xml. Добавьте следующие файлы библиотеки в WEB-INF/lib:

  • commons-logging-1.1.1.jar
  • log4j-1.2.15.jar
  • twitter4j-2.0.9.jar

Сейчас я хочу напомнить об использовании Twitter4J 2.0.9+, поскольку настройка URL обратного вызова поддерживается только начиная с версии 2.0.9 Twitter4J. По умолчанию URL обратного вызова настроен в файле web.xml на localhost. (Twitter4J – это Java™-библиотека для TwitterAPI с открытыми исходными кодами; см. раздел Ресурсы.) После компилирования и сборки приложения в форме файла MyTtWebClient.war разверните его в Tomcat и попробуйте обратиться к нему по адресу http://localhost:8080/MyTtWebClient.

Основным элементом приложения MyTtWebClient является сервлет MyTwitterServlet (полный исходный код доступен по ссылке, приведенной в разделе Загрузка). Этот сервлет определяется в классе myttwebclient.MyTwitterServlet. Метод doPost(HttpServletRequest request, HttpServletResponse response) отвечает за аутентификацию OAuth, обновление и удаление статуса пользователя в Twitter, а также за отображение лент новостей от друзей.

Метод doPost(...) обрабатывает как аутентификацию OAuth, так и различные взаимодействия с login_twitter.html и update_twitter_status.jsp. Страница приветствия данного приложения, login_twitter.html, предоставляет кнопку для регистрации пользователя в Twitter; см. рисунок 1. После нажатия пользователем этой кнопки вызывается метод doPost(...). Существует две ситуации: новый пользователь или вернувшийся пользователь. Как показано в листинге 1, код пытается загрузить Twitter ID пользователя из cookie-файла. Если он не загружается, пользователь будет рассматриваться как новый. Из Twitter будет запрошен маркер запроса, после чего пользователь будет направлен в Twitter для авторизации нашего кода к пользовательским данным на Twitter с правами доступа чтение/запись (см. рисунок 2). Если все проходит нормально, Twitter направит пользователя по URL-адресу обратного вызова, установленному в web.xml. В данном случае я задал этот URL так, чтобы он указывал на сервлет MyTtServlet. К этому времени маркер запроса авторизуется и его можно поменять в Twitter на маркер доступа. После извлечения маркер доступа будет сохраняться в файле WEB-INF/token.txt для последующего использования. В реальных приложениях вы, вероятно, будете сохранять маркер доступа в базе данных. Кроме того, в браузере пользователя будут сохраняться cookie, для того чтобы в следующий раз мы могли проверить, работал ли пользователь с нашим приложением ранее. Теперь пользователь направляется на страницу update_twitter_status.jsp. Успешная регистрация показана на рисунке 3, на котором выводится последнее обновление пользователя и некоторые ленты новостей от друзей.

Листинг 1. Аутентификация OAuth с Twitter
protected void doPost(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {
	HttpSession session = request.getSession();

	// Обратный вызов из Twitter
	String oauthToken = request.getParameter(PARAM_OAUTH_TOKEN);
	if (oauthToken != null) {
		logger.debug(PARAM_OAUTH_TOKEN + " received from Twitter");
		try {
			Twitter twitter = (Twitter) session.getAttribute(ATTR_TWITTER);
			RequestToken requestToken = (RequestToken) session
					.getAttribute(ATTR_REQUEST_TOKEN);
			AccessToken accessToken;
			if (callbackUrl == null) {
				accessToken = twitter.getOAuthAccessToken(requestToken);
			} else {
				String oauthVerifier = request
						.getParameter(PARAM_OAUTH_VERIFIER);
				logger.debug(PARAM_OAUTH_VERIFIER
						+ " received from Twitter");
				accessToken = twitter.getOAuthAccessToken(requestToken
					.getToken(), requestToken.getTokenSecret(),
					oauthVerifier);
			}
			twitter.setOAuthAccessToken(accessToken);
			session.removeAttribute(ATTR_REQUEST_TOKEN);
			session.setAttribute(ATTR_TWITTER, twitter);

			int id = twitter.verifyCredentials().getId();
			logger.debug("Access token retrieved for user " + id
					+ " from Twitter");
			storeAccessToken(id, accessToken);
			Cookie cookie = new Cookie(COOKIE_TWITTER_ID, " + id);
			cookie.setMaxAge(63072000); // Valid for 2 years
			response.addCookie(cookie);
			logger.debug("Cookie set for user " + id);

			// Получить последний статус и ленту новостей от друзей
			getMyLastStatusAndStoreInSession(session);
			getFriendsTimelinesAndStoreInSession(session);

			// Перейти на страницу статуса обновления 
			request.getRequestDispatcher(PAGE_UPDATE_STATUS).forward(
					request, response);
		} catch (TwitterException e) {
			logger.error("Failed to retrieve access token - "
					+ e.getMessage());
			throw new ServletException(e);
		}
	}

	// Действия в этом приложении
	String action = request.getParameter(PARAM_ACTION);
	if (ACTION_SIGN_IN.equals(action)) {
		logger.debug("Signing in with Twitter...");
		Twitter twitter = new Twitter();
		twitter.setOAuthConsumer(consumerKey, consumerSecret);

		// Попытаться загрузить Twitter ID из cookie
		String id = null;
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			Cookie cookie;
			for (int i = 0; i < cookies.length; i++) {
				cookie = cookies[i];
				if (COOKIE_TWITTER_ID.equals(cookie.getName())) {
					id = cookie.getValue();
				}
			}
		}

		// Попытаться загрузить маркер доступа, если был извлечен Twitter ID 
		AccessToken accessToken = null;
		if (id != null) {
			accessToken = loadAccessToken(id);
			if (accessToken != null) {
				twitter.setOAuthAccessToken(accessToken);
				session.setAttribute(ATTR_TWITTER, twitter);

				// Получить последний статус и ленту новостей от друзей
				try {
					getMyLastStatusAndStoreInSession(session);
					getFriendsTimelinesAndStoreInSession(
						session, true);
				} catch (TwitterException e) {
					e.printStackTrace();
				}

				// Обратиться к загруженному маркеру, перейти к 
				// странице обновленного статуса
				logger.debug("Going to the status update page...");
				request.getRequestDispatcher(PAGE_UPDATE_STATUS).forward(
						request, response);
			}
		}

		// Невозможно загрузить маркер доступа, 
		// перейти в Twitter для аутентификации
		if (accessToken == null) {
			try {
				RequestToken requestToken;
				if (callbackUrl == null) {
					requestToken = twitter.getOAuthRequestToken();
				} else {
					requestToken =
						twitter.getOAuthRequestToken(callbackUrl);
				}
				String authorisationUrl = requestToken
						.getAuthorizationURL();
				session.setAttribute(ATTR_TWITTER, twitter);
				session.setAttribute(ATTR_REQUEST_TOKEN, requestToken);

				logger.debug("Redirecting user to " + authorisationUrl);
				response.sendRedirect(authorisationUrl);
			} catch (TwitterException e) {
				logger.error("Sign in with Twitter failed - "
						+ e.getMessage());
				throw new ServletException(e);
			}
		}

	} else if (ACTION_UPDATE.equals(action)) {
	// Обработать ACTION_UPDATE, ACTION_DELETE, ACTION_MORE and ACTION_LATEST
	......
}

Если MyTwitterServlet может загрузить пользовательские cookie после нажатия им кнопки sign-in, этот пользователь будет рассматриваться как уже работавший с приложением. Как видно из листинга 1, маркер доступа пользователя может быть извлечен из token.txt. Следовательно, нет необходимости связываться с Twitter для повторной аутентификации пользователя. Пользователь будет направлен на страницу updatee_twitter_status.jsp после того, как информация о его статусе и ленты новостей от его друзей будут извлечены с сайта Twitter (см. рисунок 3).

Если вы работали с приложением MyTtDesktopClient в первой части данной серии статей (EN), то, наверное, помните, что нужно было вводить PIN, возвращенный с сайта Twitter после предоставления доступа к данным на Twitter. В этот раз, поскольку можно использовать перенаправление в наш сервлет, мы выбрали тип приложения Browser во время регистрации. Таким образом улучшается работа с пользователем.

Рисунок 1. Страница приветствия MyTtWebClient
Рисунок 1. Страница приветствия MyTtWebClient
Рисунок 1. Страница приветствия MyTtWebClient
Рисунок 2. Предоставление доступа к MyTtWebClient
Рисунок 2. Предоставление доступа к MyTtWebClient
Рисунок 2. Предоставление доступа к MyTtWebClient
Рисунок 3. MyTtWebClient после аутентификации OAuth
Рисунок 3. MyTtWebClient после аутентификации OAuth
Рисунок 3. MyTtWebClient после аутентификации OAuth

Оставшаяся часть метода doPost(...) приведена в листинге 2. Этот фрагмент кода отвечает за действия трех кнопок, отображенных на рисунке 3, и ссылки на удаление в конце информации о последнем обновлении. Используя их, пользователь может удалить свое последнее обновление, обновить свой статус и просмотреть ленту новостей от своих друзей. Для совершенствования кода можно применить Ajax, используя, например, Google Web Toolkit (GWT) для улучшения удобства работы пользователей. Я оставлю это в качестве домашнего задания. Снимок экрана после успешного обновления статуса изображен на рисунке 4.

Листинг 2. Действия, поддерживаемые в myttwebclient.MyTwitterServlet
protected void doPost(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {
	HttpSession session = request.getSession();

	// Поддержка аутентификации OAuth 
	......

	} else if (ACTION_UPDATE.equals(action)) {
		logger.debug("Updating Twitter status...");
		String status = request.getParameter(PARAM_STATUS);
		Twitter twitter = (Twitter) session.getAttribute(ATTR_TWITTER);
		try {
			Status twitterStatus = twitter.updateStatus(status);
			logger.debug("Successfully updated the status to ["
					+ twitterStatus.getText() + "].");
			// Обновление последнего статуса
			session.setAttribute(ATTR_LAST_UPDATED_STATUS, twitterStatus
					.getText()
					+ " " + twitterStatus.getCreatedAt());
			session.setAttribute(ATTR_LAST_UPDATED_STATUS_ID, "
					+ twitterStatus.getId());

			// Обновление ленты новостей от друзей
			getFriendsTimelinesAndStoreInSession(session, true);

			// Оставаться на странице обновления статуса
			logger.debug("Staying in the status update page...");
			request.getRequestDispatcher(PAGE_UPDATE_STATUS).forward(
					request, response);
		} catch (TwitterException e) {
			logger.error("Failed to update Twitter status - "
					+ e.getMessage());
			throw new ServletException(e);
		}
	} else if (ACTION_DELETE.equals(action)) {
		logger.debug("Deleting Twitter status...");
		String strId = (String) session
				.getAttribute(ATTR_LAST_UPDATED_STATUS_ID);
		if (strId != null & strId != ") {
			Twitter twitter = (Twitter) session.getAttribute(ATTR_TWITTER);
			try {
				int id = twitter.verifyCredentials().getId();
				twitter.destroyStatus(Long.parseLong(strId));
				session.removeAttribute(ATTR_LAST_UPDATED_STATUS);
				session.removeAttribute(ATTR_LAST_UPDATED_STATUS_ID);
				logger.debug("Last update deleted for Twitter user " + id
						+ " deleted, session record removed");

				// Получить последний статус и ленты новостей от друзей
				getMyLastStatusAndStoreInSession(session);
				getFriendsTimelinesAndStoreInSession(session, true);
			} catch (TwitterException e) {
				logger.error("Failed to delete Twitter status - "
						+ e.getMessage());
				throw new ServletException(e);
			}
		}

		// Оставаться на странице обновления статуса
		logger.debug("Staying in the status update page...");
		request.getRequestDispatcher(PAGE_UPDATE_STATUS).forward(request,
				response);
	} else if (ACTION_MORE.equals(action)) {
		// Обновить ленты новостей от друзей
		getFriendsTimelinesAndStoreInSession(session);

		// Оставаться на странице обновления статуса
		logger.debug("Staying in the status update page...");
		request.getRequestDispatcher(PAGE_UPDATE_STATUS).forward(request,
				response);
	} else if (ACTION_LATEST.equals(action)) {
		// Обновить последние ленты новостей от друзей
		getFriendsTimelinesAndStoreInSession(session, true);

		// Оставаться на странице обновления статуса
		logger.debug("Staying in the status update page...");
		request.getRequestDispatcher(PAGE_UPDATE_STATUS).forward(request,
				response);
	}
}
Рисунок 4. Статус Twitter, обновленный приложением MyTtWebClient
Рисунок 4. Twitter-статус, обновленный приложением MyTtWebClient
Рисунок 4. Twitter-статус, обновленный приложением MyTtWebClient

Я полагаю, теперь вы имеете полную картину приложения MyTtWebClient. Если вы хотите развернуть его на Web-сервере, поддержка обратного вызова может больше не понадобиться. Для ее отмены просто укажите параметр callbackUrl в виде пустой строки в файле WEB-INF/web.xml. Но помните, что необходим правильный URL-адрес обратного вызова в Twitter, чтобы он знал, куда направить пользователя после успешной аутентификации OAuth.

Перед вводом вашего Web-приложения в эксплуатацию вы должны знать об ограничении, накладываемом сайтом Twitter на API-вызовы. Например, предельная скорость для REST API-вызовов по умолчанию установлена в значение 150 вызовов в час. К счастью, Twitter позволяет применить 20 000 запросов в час. Дополнительная информация приведена на странице Twitter FAQ (см. раздел "Ресурсы").

Резюме

Во второй части данной серии статей я рассказал о том, как разработать клиентское Web-приложение для Twitter, MyTtWebClient. Это Web-приложение демонстрирует, насколько прозрачно OAuth работает с Web-браузерами. Я также добавил в MyTtWebClient несколько дополнительных функций по сравнению с MyTtDesktopClient, включая удаление последнего обновления и отображение лент новостей от друзей. В третьей части я продемонстрирую, как выполнить перенос этого Web-приложения в среду Google App Engine.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Web-архитектура, SOA и web-сервисы
ArticleID=778852
ArticleTitle=Доступ к Web-сайтам социальных сетей по протоколу OAuth: Часть 2. Создание клиентского Web-приложения для Twitter, использующего OAuth
publish-date=12052011