Как запрашивать страницы с сайта, использующего OpenID?
Этот вопрос задан здесь до. Принятый ответ, вероятно, был очевидным как для допрашивающего, так и для ответчика, но не для меня. Я прокомментировал вышеупомянутый вопрос, чтобы получить больше указаний, но ответа не было. Я также подошел к мета-Q & A для помощи в том, как вернуть вопросы из их могилы, и не получил ответа.
Ответ на вышеупомянутый вопрос:
С точки зрения клиента, идентификатор OpenID очень похож на любой другой веб-логин. Для клиента нет определенного протокола; это обычный веб-сеанс, который зависит от вашего провайдера OpenID. По этой причине я сомневаюсь, что существуют такие библиотеки. Вероятно, вам придется самому закодировать его.
Я знаю, как войти на сайт с Python уже с помощью Urllib2. Но этого недостаточно, чтобы угадать, как аутентифицироваться на OpenID.
Я действительно пытаюсь получить мой почтовый ящик StackOverflow в формате json, для которого мне нужно войти в систему.
Может ли кто-нибудь предоставить краткое введение или ссылку на хороший учебник о том, как это сделать?
Ответы
Ответ 1
Этот ответ подводит итог тому, что сказано ниже, особенно RedBaron, а также добавление метода, который я использовал для входа в папку "Входящие" StackOverflow с помощью учетных записей Google.
Используя инструмент разработчика Tamper Data для Firefox и входящий в StackOVerflow, можно увидеть, что OpenID работает следующим образом:
- StackOverflow запрашивает аутентификацию из данной службы (здесь Google), определенной в опубликованных данных;
- Учетные записи Google принимают и проверяют наличие уже существующего файла cookie в качестве доказательства аутентификации;
- Если cookie не найден, Google запрашивает аутентификацию и устанавливает cookie;
- После того, как cookie установлен, StackOverflow подтверждает аутентификацию пользователя.
Выше суммируется процесс, который на самом деле более сложный, поскольку на самом деле происходит много переадресаций и обмен файлов cookie.
Поскольку воспроизведение одного и того же процесса программно оказалось чем-то трудным (и это может быть просто моя неграмотность), особенно пытаясь выследить URL-адреса для вызова со всеми языковыми особенностями и т.д., я решил сначала войти в учетные записи Google, запустил cookie, а затем войдите в Stackoverflow, который будет использовать cookie для аутентификации.
Это делается просто с использованием следующих модулей Python: urllib, urllib2, cookielib и BeautifulSoup.
Вот (упрощенный) код, он не идеален, но он делает трюк. Расширенную версию можно найти на Github.
#!/usr/bin/env python
import urllib
import urllib2
import cookielib
from BeautifulSoup import BeautifulSoup
from getpass import getpass
# Define URLs
google_accounts_url = 'http://accounts.google.com'
authentication_url = 'https://accounts.google.com/ServiceLoginAuth'
stack_overflow_url = 'https://stackoverflow.com/users/authenticate'
genuwine_url = 'https://stackoverflow.com/inbox/genuwine'
# Build opener
jar = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar))
def request_url(request):
'''
Requests given URL.
'''
try:
response = opener.open(request)
except:
raise
return response
def authenticate(username='', password=''):
'''
Authenticates to Google Accounts using user-provided username and password,
then authenticates to StackOverflow.
'''
# Build up headers
user_agent = 'Mozilla/5.0 (Ubuntu; X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0'
headers = {'User-Agent' : user_agent}
# Set Data to None
data = None
# Build up URL request with headers and data
request = urllib2.Request(google_accounts_url, data, headers)
response = request_url(request)
# Build up POST data for authentication
html = response.read()
dsh = BeautifulSoup(html).findAll(attrs={'name' : 'dsh'})[0].get('value').encode()
auto = response.headers.getheader('X-Auto-Login')
follow_up = urllib.unquote(urllib.unquote(auto)).split('continue=')[-1]
galx = jar._cookies['accounts.google.com']['/']['GALX'].value
values = {'continue' : follow_up,
'followup' : follow_up,
'dsh' : dsh,
'GALX' : galx,
'pstMsg' : 1,
'dnConn' : 'https://accounts.youtube.com',
'checkConnection' : '',
'checkedDomains' : '',
'timeStmp' : '',
'secTok' : '',
'Email' : username,
'Passwd' : password,
'signIn' : 'Sign in',
'PersistentCookie' : 'yes',
'rmShown' : 1}
data = urllib.urlencode(values)
# Build up URL for authentication
request = urllib2.Request(authentication_url, data, headers)
response = request_url(request)
# Check if logged in
if response.url != request._Request__original:
print '\n Logged in :)\n'
else:
print '\n Log in failed :(\n'
# Build OpenID Data
values = {'oauth_version' : '',
'oauth_server' : '',
'openid_username' : '',
'openid_identifier' : 'https://www.google.com/accounts/o8/id'}
data = urllib.urlencode(values)
# Build up URL for OpenID authetication
request = urllib2.Request(stack_overflow_url, data, headers)
response = request_url(request)
# Retrieve Genuwine
data = None
request = urllib2.Request(genuwine_url, data, headers)
response = request_url(request)
print response.read()
if __name__ == '__main__':
username = raw_input('Enter your Gmail address: ')
password = getpass('Enter your password: ')
authenticate(username, password)
Ответ 2
Ну, я сам мало знаю об OpenID, но ваш пост (и щедрость!!) меня заинтересовал.
Эта ссылка сообщает точный поток последовательности проверки OpenID (Atleast for v1.0. Новая версия 2.0). Из того, что я мог разобрать, шаги были бы чем-то вроде
- Вы получаете страницу входа в систему stackoverflow, которая также предоставляет возможность входа в систему с использованием OpenID (как поле формы).
- Вы отправляете ur openID, который на самом деле является формой uri и NOT username/email (если это профиль Google, это ваш профиль)
- Затем Stackoverflow подключится к вашему провайдеру ID (в данном случае google) и отправит вам переадресацию на страницу входа в google и другую ссылку туда, куда вы должны перенаправить позже (скажем a)
- Вы можете войти на страницу, предоставленную Google, условно (используя метод POST с Python)
- Google предоставляет криптографический токен (не совсем уверен в этом шаге) в ответ на ваш запрос на вход
- Вы отправляете новый запрос в этот токен.
- Stackoverflow свяжется с Google с этим токеном. Если аутентификация установлена, она вернет идентификатор сеанса
- Позднее запросы к STackOverflow должны иметь этот идентификатор сеанса
- Не знаю, как выйти из системы!
Эта ссылка рассказывает о различных ответах в OpenID и о том, что они означают. Так что, возможно, это пригодится, когда ваш код будет вашим клиентом.
Ссылки со страницы wiki OpenID Explained
РЕДАКТИРОВАТЬ: Использование данных Tamper Добавить для Firefox, можно создать следующую последовательность событий.
- Пользователь отправляет запрос на страницу входа в систему SO. При вводе openID в поле формы результирующая страница отправляет перенаправление 302 на страницу google.
URL-адрес перенаправления содержит множество параметров OpenID (которые относятся к серверу google). Один из них - return_to = https://stackoverflow.com/users/authenticate/?s=some_value.
- Пользователь получает страницу входа google. При входе в систему существует несколько 302, которые перенаправляют пользователя в области google.
- Наконец, получено 302, которое перенаправляет пользователя на страницу stackoverflow, указанную в 'return_to' ранее
- В течение всей этой серии операций было создано много файлов cookie, которые должны храниться правильно.
- При доступе к странице SO (которая была отправлена Google google) 302 сервер SO обрабатывает ваш запрос, а в заголовке ответа отправляет поле "Set-Cookie" для установки файлов cookie с именем gauth и usr со значением вместе с другим 302 - stackoverflow.com. Этот шаг завершает ваш логин
- Ваш клиент просто сохраняет cookie usr
- Вы вошли в систему, пока вы помните, чтобы отправить Cookie usr с любым запросом SO.
- Теперь вы можете запросить свой почтовый ящик только для того, чтобы отправить файл cookie usr с запросом.
Я предлагаю вам начать кодирование своего клиента python и тщательно изучить ответы. В большинстве случаев это будет серия из 302 с минимальным вмешательством пользователя (за исключением того, что вы заполняете свое имя пользователя и пароль Google и разрешаете страницу сайта).
Однако, чтобы упростить работу, вы можете просто войти в SO с помощью своего браузера, скопировать все значения cookie и сделать запрос с помощью urllib2 с установленными значениями cookie.
Конечно, если вы выйдете из браузера, вам придется снова войти в систему и изменить значение cookie в вашей программе python.
Ответ 3
Я знаю, что это близко к археологии, копая сообщение, которое два года назад, но я только что написал новую улучшенную версию кода из утвержденного ответа, поэтому я подумал, что это может быть здорово поделиться этим здесь, так как этот вопрос/ответы были большой помощью для меня, чтобы реализовать это.
Итак, вот что другое:
- он использует новую библиотеку
requests
, которая является улучшением над urllib2
;
- он поддерживает аутентификацию с помощью поставщика google и stackexchange openid.
- это намного короче и проще читать, хотя у него меньше распечаток
здесь код:
#!/usr/bin/env python
import sys
import urllib
import requests
from BeautifulSoup import BeautifulSoup
def get_google_auth_session(username, password):
session = requests.Session()
google_accounts_url = 'http://accounts.google.com'
authentication_url = 'https://accounts.google.com/ServiceLoginAuth'
stack_overflow_url = 'http://stackoverflow.com/users/authenticate'
r = session.get(google_accounts_url)
dsh = BeautifulSoup(r.text).findAll(attrs={'name' : 'dsh'})[0].get('value').encode()
auto = r.headers['X-Auto-Login']
follow_up = urllib.unquote(urllib.unquote(auto)).split('continue=')[-1]
galx = r.cookies['GALX']
payload = {'continue' : follow_up,
'followup' : follow_up,
'dsh' : dsh,
'GALX' : galx,
'pstMsg' : 1,
'dnConn' : 'https://accounts.youtube.com',
'checkConnection' : '',
'checkedDomains' : '',
'timeStmp' : '',
'secTok' : '',
'Email' : username,
'Passwd' : password,
'signIn' : 'Sign in',
'PersistentCookie' : 'yes',
'rmShown' : 1}
r = session.post(authentication_url, data=payload)
if r.url != authentication_url: # XXX
print "Logged in"
else:
print "login failed"
sys.exit(1)
payload = {'oauth_version' : '',
'oauth_server' : '',
'openid_username' : '',
'openid_identifier' : ''}
r = session.post(stack_overflow_url, data=payload)
return session
def get_so_auth_session(email, password):
session = requests.Session()
r = session.get('http://stackoverflow.com/users/login')
fkey = BeautifulSoup(r.text).findAll(attrs={'name' : 'fkey'})[0]['value']
payload = {'openid_identifier': 'https://openid.stackexchange.com',
'openid_username': '',
'oauth_version': '',
'oauth_server': '',
'fkey': fkey,
}
r = session.post('http://stackoverflow.com/users/authenticate', allow_redirects=True, data=payload)
fkey = BeautifulSoup(r.text).findAll(attrs={'name' : 'fkey'})[0]['value']
session_name = BeautifulSoup(r.text).findAll(attrs={'name' : 'session'})[0]['value']
payload = {'email': email,
'password': password,
'fkey': fkey,
'session': session_name}
r = session.post('https://openid.stackexchange.com/account/login/submit', data=payload)
# check if url changed for error detection
error = BeautifulSoup(r.text).findAll(attrs={'class' : 'error'})
if len(error) != 0:
print "ERROR:", error[0].text
sys.exit(1)
return session
if __name__ == "__main__":
prov = raw_input('Choose your openid provider [1 for StackOverflow, 2 for Google]: ')
name = raw_input('Enter your OpenID address: ')
pswd = getpass('Enter your password: ')
if '1' in prov:
so = get_so_auth_session(name, pswd)
elif '2' in prov:
so = get_google_auth_session(name, pswd)
else:
print "Error no openid provider given"
r = so.get('http://stackoverflow.com/inbox/genuwine')
print r.json()
код также доступен как github gist
НТН
Ответ 4
Вам нужно внедрить куки файлы на любой странице входа в систему, в Python вы используете cookiejar. Например:
jar = cookielib.CookieJar()
myopener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar))
#myopener now supports cookies.
....
Ответ 5
Я сделал простой script, который входит в систему stackoverflow.com, используя файлы cookie Mozilla Firefox. Он не полностью автоматизирован, потому что вам нужно войти в систему вручную, но все, что мне удалось сделать.
Scipt является актуальным для последних версий FF (я использую 8.0.1), но вам нужно получить последнюю dll sqlite, потому что по умолчанию, который поставляется с python 2.7, невозможно открыть БД. Вы можете получить его здесь: http://www.sqlite.org/sqlite-dll-win32-x86-3070900.zip
import urllib2
import webbrowser
import cookielib
import os
import sqlite3
import re
from time import sleep
#login in Firefox. Must be default browser. In other cases log in manually
webbrowser.open_new('http://stackoverflow.com/users/login')
#wait for user to log in
sleep(60)
#Process profiles.ini to get path to cookies.sqlite
profile = open(os.path.join(os.environ['APPDATA'],'Mozilla','Firefox','profiles.ini'), 'r').read()
COOKIE_DB = os.path.join(os.environ['APPDATA'],'Mozilla','Firefox','Profiles',re.findall('Profiles/(.*)\n',profile)[0],'cookies.sqlite')
CONTENTS = "host, path, isSecure, expiry, name, value"
#extract cookies for specific host
def get_cookies(host):
cj = cookielib.LWPCookieJar()
con = sqlite3.connect(COOKIE_DB)
cur = con.cursor()
sql = "SELECT {c} FROM moz_cookies WHERE host LIKE '%{h}%'".format(c=CONTENTS, h=host)
cur.execute(sql)
for item in cur.fetchall():
c = cookielib.Cookie(0, item[4], item[5],
None, False,
item[0], item[0].startswith('.'), item[0].startswith('.'),
item[1], False,
item[2],
item[3], item[3]=="",
None, None, {})
cj.set_cookie(c)
return cj
host = 'stackoverflow'
cj = get_cookies(host)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
response = opener.open('http://stackoverflow.com').read()
# if username in response - Auth successful
if 'Stanislav Golovanov' in response:
print 'Auth successful'