Кроме авторизации в приложениях для Facebook в ходе работы над проектом была решена еще одна задача – авторизация в приложениях для ВКонтакте. Как и в случае с Facebook, у меня было сильное желание не делать два раза одну и ту же работу, а использовать одну и ту же базу пользователей и один и тот же механизм для авторизации через сайт ВКонтакте и для авторизации в iframe-приложении ВКонтакте. Это удалось решить без особых сложностей, и вот наконец пришло время сорвать покров тайны с некоторых загадочных настроек.
Особенности ВКонтакте
В отличие от Facebook, у ВКонтакте есть одна принципиальная особенность, которая несколько затрудняет решение этой задачи, а именно: вы не можете использовать одно и то же приложение для авторизации через OAuth и для авторизации в iframe-приложении. Вам необходимо зарегистрировать iframe-приложение для ВКонтакте отдельно и получить для него id и secret.
Другая особенность, которая, наоборот, упрощает работу, заключается в том, что ВКонтакте не делает POST-запрос при переходе на URL вашего приложения, а использует метод GET. То есть, минус одна заморочка с CSRF.
В целом для ВКонтакте используется тот же принцип, что и для Facebook, а именно:
- При обращении к view приложения происходит проверка: через какой backend авторизован пользователь;
- Если это ВКонтакте, то мы выбираем из базы access_token и используем его для работы с API;
- Если нет – мы используем полученный запрос для авторизации;
- Доработанный Backend для ВКонтакте разбирает запрос и производит авторизацию с учетом того, что могла использоваться как авторизация через сайт, так и авторизация через приложение.
Начнем по порядку.
Проверка авторизации
Чтобы убедиться, что пользователь нашего view авторизован через нужный нам backend, используется функция is_complete_authorization
# Checks the completeness of current user authentication; complete = logged via VKontakte backend
def is_complete_authentication(request):
return request.user.is_authenticated() and VKontakteOAuth2Backend.__name__ in request.session.get(BACKEND_SESSION_KEY, '')
Декоратор для view приложения
Декоратор выглядит чуть проще, чем для Facebook, так как не нужно разбирать signed_request.
def vkontakte_intro(func):
def wrapper(request, *args, **kwargs):
# User must me logged via VKontakte backend in order to ensure we talk about the same person
if not is_complete_authentication(request):
try:
social_complete(request, VKontakteOAuth2Backend.name)
except (ValueError, AttributeError):
pass
# Need to re-check the completion
if is_complete_authentication(request):
kwargs.update({'access_token': get_access_token(request.user)})
else:
request.user = AnonymousUser()
return func(request, *args, **kwargs)
return wrapper
Назначение у функции get_access_token: вытащить из базы или из кэша access_token для указанного пользователя. Пример:
VK_AT_CACHE_PREFIX = 'VK_AT_%s'
# Returns cached access token for the user; loads it from db if needed
def get_access_token(user):
key = VK_AT_CACHE_PREFIX % str(user.id)
access_token = cache.get(key)
# If cache is empty read the database
if access_token is None:
try:
social_user = user.social_user if hasattr(user, 'social_user') else UserSocialAuth.objects.get(user=user.id, provider=VKontakteOAuth2Backend.name)
except UserSocialAuth.DoesNotExist:
return None
if social_user.extra_data:
access_token = social_user.extra_data.get('access_token')
expires = social_user.extra_data.get('expires')
cache.set(key, access_token, int(expires) if expires is not None else 0)
return access_token
Подключение к приложению
Для работы некоторых методов API вы должны запросить у пользователя установку вашего приложения и нужные вам права. Это две разные операции, первая из которых запускается при вызове функции startConnect, а вторая – следом за ней, в функции requestRights.
{% block head %}
<script src="http://vkontakte.ru/js/api/xd_connection.js?2" type="text/javascript"></script>
{% endblock %}
{% block js %}
<script type="text/javascript">
VK.init(function() {
// any of your code here
}
);
function startConnect() {
VK.callMethod('showInstallBox');
}
function requestRights() {
VK.callMethod('showSettingsBox', 1 + 2); // 1+2 is just an example
}
function onSettingsChanged(settings) {
window.location.reload();
}
$(document).ready( function(){
VK.addCallback("onApplicationAdded", requestRights);
VK.addCallback("onSettingsChanged", onSettingsChanged);
});
</script>
{% endblock %}
Необходимые настройки
Для того чтобы авторизация через приложение начала работать, нужно сделать следующие настройки:
VKONTAKTE_APP_AUTH={'key':'iframe_app_secret_key', 'user_mode': 2, 'id':'iframe_app_id'}
Параметр user_mode может принимать значения 0, 1 или 2, он влияет на проверку того, подключился пользователь к вашему приложению или нет. Если поставить user_mode в 0, то никакой проверки произведено не будет и авторизация успешно пройдет в любом случае. При user_mode=1 будет проведена проверка на значение параметра is_app_user. Этот параметр приходит в GET-запросе, который присылает ВКонтакте на URL вашего приложения при начале работы с ним. Авторизация будет успешной, только если пользователь подключен к вашему приложению. Однако может случиться так, что пользователь подключился к вашему приложению позже, а запрос уже был проанализирован, is_app_user был 0, а в браузере пользователь уже давно ушел на другую страницу. Для этого используется значение 2, которое делает запрос к API и проверяет, подключил пользователь ваше приложение или нет. Лично я пользуюсь последним вариантом.
Значение key используется для проверки авторизации, id – для выполнения запросов к API. Оно имеет более высокий приоритет по отношению к VKONTAKTE_APP_ID, потому что именно для него вы получаете права от пользователя в интерфейсе.
Если вы не хотите использовать авторизацию через приложение, просто не используйте VKONTAKTE_APP_AUTH совсем.
Update
Пример использования добавлен в главную ветку 23 августа 2012.