Что случилось?
Здравствуй, дорогой читатель. Если тебе хотя бы однажды доводилось работать с API Вконтакте и при этом писать все на python, вероятно, авторизация приложения заставила тебя сделать несколько приседаний, после которых ног либо не чувствуешь и падаешь в обморок, либо вкачиваешь квадрицепс и все же пробиваешь API, как Ван Дамм.
По какой-то причине этот, казалось бы, самый непримечательный этап поначалу отнимает огромное количество сил и времени. Моя задача: помочь читателям Хабра избежать травм ног.
Далее я предлагаю рассмотреть небольшую библиотеку, позволяющую в одну строчку авторизовать свое приложение для конкретного пользователя и получить access_token. В конце статьи представлена ссылка на github-репозиторий этой библиотеки с quickstart’ом в README-файле.
Авторизация через ВКонтакте
Сколько процентов пользователей вашего сайта являются также пользователями ВКонтакте? Как по вашему, сколько человек ничего не пишут / комментируют / добавляют (нужное подчеркнуть), лишь потому, что им лень регистрироваться на еще одном непонятном сайте в 100й раз? Предлагаю ответить для себя на эти 2 вопроса, прежде, чем ругать ВКонтакте и Open API. В моем случае на сайт из ВКонтакте каждый день приходят около 1500 человек и обеспечить им простой и удобный способ регистрации, как мне кажется, является моим долгом.
Вряд ли я открою что то новое, но если, хотя бы еще 1 сайт станет немного удобнее после этой статьи — значит я не зря потратил свое время на написание этого текста. Я писал модуль Open API авторизации для сайта на PHP, поэтому весь код будет на нем. Для Django также была статья.
Исходный код простейшего примера доступен на github’е. Здесь его перепечатывать не буду, лишь вкратце расскажу, как это работает.
Основную работу выполняет класс Auth_Vkontakte, содержащий 3 метода:
- is_auth
— Возвращает ID пользователя ВКонтакте, в случае, если пользователь не авторизован через Open API — возвращает false - logout
— Разлогинивает пользователя, очищая куку, которую добавляет ВКонтакте. Лучшего способа я не нашел. Есть у Open API метод logout, но у меня он работал через раз. - render_login_form
— Возвращает HTML код для отображения кнопки «Войти ВКонтакте», включая все необходимые script’ы.
Вам, конечно, придется также добавить поддержку vkontakte в ваш движок сайта, например, добавить в табличку пользователя поле «vk_id», в котором будет хранится ID пользователя ВКонтакте.
Алгоритм работы в реальных условиях примерно такой:
- После входа пользователя вконтакте перекидываем его на отдельную страницу (в моем случае это vk.php), где проверяем, зарегистрирован ли уже пользователь с таким vk_id. Если нет — показываем ему упрощенную форму регистрации (например, только логин и email). После чего создаем пользователя и перекидываем только что зарегистрированного посетителя на главную страницу.
- Создаем backend, который будет проверять куку ВКонтакте через Auth_Vkontakte::is_auth, в случае, когда посетитель не вошел на ваш сайт никаким способом. Если is_auth возвращает значение, отличное от false и пользователь с таким id зарегистирован на вашем сайте — авторизируем через вашу систему пользователей. Если вдруг так оказалось, что он не зарегистирован — вновь показываем форму регистрации.
- При logout удаляем кроме вашей куки также куку из ВКонтакте (метод Auth_Vkontakte::logout)
Вообще, как мне кажется, подобными примерами должна начинаться любая документация по любому API. Разработчики ВКонтакте, однако, так не думают и понять Open API по их документации невозможно. Фактически, я ей и не пользовался — все прочитал лишь в исходниках на durov.at. Неужто компания ВКонтакте не может позволить себе нанять нормального технического писателя, который бы писал примеры и нормальные мануалы, а не сухие списки функций с кратким описанием параметров, которые она принимает?
Для того, что попробовать тестовый пример в работе (который, правда, ничего кроме вашего ID не покажет) достаточно скачать исходники, и настроить локальный веб-сервер на адрес: openapi.lc (добавить в hosts: 127.0.0.1 openapi.lc).
Если кому то понравилось и стало полезным — напишу также статью про FacebookConnect.
Задача
Хотим небольшой модуль, который позволяет провести авторизацию красиво, универсально и максимально надежно, а использовать который очень просто. Стоит сказать, что данное решение является усовершенствованием и обобщением варианта, предложенного в этой статье.
Итак, используем python3.5, библиотеку для html запросов requests и getpass для скрытого ввода пароля.
Наша задача: несколько раз обратиться по верному адресу, каждый раз парсить
, отправлять ответ и наконец получить желанный access_token.
Основные плюсы идентификации
Преимущества имеют как владельцы сайта, так и его пользователи. Для владельца преимуществом являются:
- Защита от спама (отсеивание спам-ботов).
- Ограничение прав использования дополнительных услуг. Для коммерческих сайтов авторизация просто необходима, так как они предоставляют свои услуги за деньги.
- Возможность узнать пользователя, что дает также свои плюсы: географическая, демографическая и иная информация о посетителях, которая позволяет настроить сайт корректно, подобрать наиболее эффективную рекламу, ключевики.
Преимущества, дающиеся пользователям:
- Также защита от спама.
- Возможность распознавания собеседника.
- Дополнительные возможности, такие как заполнение профиля, загрузка фотографии, иных файлов и так далее.
Итак, мы разобрались, что представляет собой авторизация. Что это средство защиты данных пользователя. Для сайтов она имеет большое значение. Исходя из этого, стоит со всей ответственностью отнестись к ситуации, если у вас не проходит авторизация.
Наверное, вы уже слышали о том, что сегодня можно пробить информацию практически о любом человеке через социальные сети
, а в особенности через ВКонтакте. Причем очень часто для этого вовсе не обязательно быть зарегистрированным в нем. Достаточно набрать фамилию, имя и город проживания нужного человека в поисковике и все.
Не буду подробно распинаться на тему того, почему это плохо (кто захочет, тот почитает написанную мною на этот счет статью о защите аккаунта ВКонтакте), а остановлюсь на том, как хоть чуть-чуть осложнить жизнь любопытным людям.
Реализация
Начнем с создания класса. При инициализации будем требовать список «разрешений», к которым приложение хочет получить доступ, id этого приложения и версию API VK. Плюсом добавим несколько необязательных параметров, значение каждого из которых прояснится далее.
Метод __init__
class VKAuth(object): def __init__(self, permissions, app_id, api_v, email=None, pswd=None, two_factor_auth=False, security_code=None, auto_access=True): «»» Args: permissions: list of Strings with permissions to get from API app_id: (String) vk app id that one can get from vk.com api_v: (String) vk API version «»» self.session = requests.Session() self.form_parser = FormParser() self.user_id = None self.access_token = None self.response = None self.permissions = permissions self.api_v = api_v self.app_id = app_id self.two_factor_auth= two_factor_auth self.security_code = security_code self.email = email self.pswd = pswd self.auto_access = auto_access if security_code != None and two_factor_auth == False: raise RuntimeError(‘Security code provided for non-two-factor authorization’)
Как было сказано в уже упомянутой статье, нам необходимо искусно ворочать cookie и redirect’ы. Все это за нас делает библиотека requests с объектом класса Session. Заведем и себе такой в поле self.session. Для парсинга html документа используется стандартный класс HTMLParser из модуля html.parser. Для парсера тоже написан класс (FormParser), разбирать который большого смысла нет, так как он почти полностью повторяет таковой из упомянутой статьи. Существенное отличие лишь в том, что использованный здесь позволяет изящно отклонить авторизацию приложения на последнем шаге, если вы вдруг передумали.
Поля user_id и access_token будут заполнены после успешной авторизации, response хранит в себе результат последнего html запроса.
Пользователю библиотеки предоставим один-единственный метод – authorize, который совершает 3 шага:
- запрос на авторизацию приложения
- авторизация пользователя 2.1 введение кода-ключа в случае двух-факторной авторизации
- подтверждение разрешения на использование permissions
Пройдемся по каждому шагу.
Шаг 1. Запрос на авторизацию приложения
Аккуратно составляем url запроса (про параметры можно прочитать здесь), отправляем запрос и парсим полученный html.
Метод authorize для Шага 1
def authorize(self): api_auth_url = ‘https://oauth.vk.com/authorize’ app_id = self.app_id permissions = self.permissions redirect_uri = ‘https://oauth.vk.com/blank.html’ display = ‘wap’ api_version = self.api_v auth_url_template = ‘{0}?client_id={1}&scope={2}&redirect_uri={3}&display={4}&v={5}&response_type=token’ auth_url = auth_url_template.format(api_auth_url, app_id, ‘,’.join(permissions), redirect_uri, display, api_version) self.response = self.session.get(auth_url) # look for element in response html and parse it if not self._parse_form(): raise RuntimeError(‘No element found. Please, check url address’)
Шаг 2. Авторизация пользователя
Реализованы методы _log_in() и _two_fact_auth() для [не]успешной авторизации пользователя в вк, если он не авторизован (а он точно не авторизован). Оба метода используют ранее определенные поля email, pswd, two_factor_auth и security_code. Если какое-то из полей не было подано аргументом при инициализации объекта класса VKAuth, их попросят ввести в консоли, а случае неудачи попросят ввести заново. Двух-факторная авторизация опциональна и по умолчанию отключена, и наш модуль уведомляет пользователя о ее присутствии ошибкой.
Метод authorize для Шага 2 (продолжение Шага 1)
#look for element in response html and parse it if not self._parse_form(): raise RuntimeError(‘No element found. Please, check url address’) else: # try to log in with email and password (stored or expected to be entered) while not self._log_in(): pass; # handling two-factor authentication # expecting a security code to enter here if self.two_factor_auth: self._two_fact_auth()
Метод _log_in для Шага 2
def _log_in(self): if self.email == None: self.email = » while self.email.strip() == »: self.email = input(‘Enter an email to log in: ‘) if self.pswd == None: self.pswd = » while self.pswd.strip() == »: self.pswd = getpass.getpass(‘Enter the password: ‘) self._submit_form({’email’: self.email, ‘pass’: self.pswd}) if not self._parse_form(): raise RuntimeError(‘No element found. Please, check url address’) # if wrong email or password if ‘pass’ in self.form_parser.params: print(‘Wrong email or password’) self.email = None self.pswd = None return False elif ‘code’ in self.form_parser.params and not self.two_factor_auth: raise RuntimeError(‘Two-factor authentication expected from VK.\nChange `two_factor_auth` to `True` and provide a security code.’) else: return True
Метод _two_fact_auth для Шага 2
def _two_fact_auth(self): prefix = ‘https://m.vk.com’ if prefix not in self.form_parser.url: self.form_parser.url = prefix + self.form_parser.url if self.security_code == None: self.security_code = input(‘Enter security code for two-factor authentication: ‘) self._submit_form({‘code’: self.security_code}) if not self._parse_form(): raise RuntimeError(‘No element found. Please, check url address’)
Создаём новое приложение «ВКонтакте»
Перед тем, как писать код, нам нужно зарегистрировать новое приложение. Делается это просто, заходим в свой профиль, переходим в раздел приложения и в нем кликаем на кнопку «Управление». В этом разделе вы увидите список всех приложений, которыми вы пользуетесь и кнопку «Создать приложение», жмём по ней. Заполняем название и выбираем пункт «Веб-сайт».
После этого появятся два новых поля, которые также заполняем и жмём «Подключить сайт». В следующем окне вам останется подтвердить регистрацию.
Вот так просто и быстро регистрируется новое приложение «ВКонтакте». Теперь переходим в настройки и копируем ID приложения и защищенный ключ в блокнот. На этом работа с социальной сетью заканчивается.