如何从使用OpenID的网站请求页面?

Ben*_*min 17 python openid authentication urllib2

之前已经在这里提出过这个问题.对于提问者和回答者来说,接受的答案可能是显而易见的 - 但不是对我而言.我已就上述问题发表评论以获得更多精确度,但没有回应.我还向meta Q&A索取了关于如何从他们的坟墓中提出问题的帮助,也没有得到答案.

上面问题的答案是:

从客户端的角度来看,OpenID登录与任何其他基于Web的登录非常相似.客户端没有定义的协议; 它是一个普通的Web会话,根据您的OpenID提供程序而有所不同.出于这个原因,我怀疑是否存在任何此类库.您可能需要自己编写代码.

我知道如何使用Urllib2模块登录使用Python的网站.但这还不足以让我猜测如何对OpenID进行身份验证.

我实际上是想以json格式获取我的StackOverflow收件箱,我需要登录.

有人可以提供一个简短的介绍或链接到一个很好的教程如何做到这一点?

Red*_*ron 11

好吧,我自己对OpenID了解不多,但你的帖子(以及赏金!!)让我感兴趣.

此链接指示OpenID身份验证序列的确切流程(Atleast for v1.0.新版本为2.0).根据我的想法,步骤将是类似的

  1. 您获取stackoverflow的登录页面,该页面还将提供使用OpenID登录的选项(作为表单字段).
  2. 你发送你的openID,这实际上是uri的一种形式,而不是用户名/电子邮件(如果是Google个人资料,则是你的个人资料ID)
  3. 那么计算器将连接到您的ID供应商(在这种情况下,谷歌),并送你一个重定向到Google登录页面,另一个链接到您稍后应该重定向(可以说)
  4. 您可以按常规方式登录谷歌提供的页面(使用Python的POST方法)
  5. Google会根据您的登录请求提供加密令牌(不太确定此步骤)
  6. 您使用此令牌将新请求发送给a.
  7. Stackoverflow将与此令牌联系谷歌.如果建立了真实性,它将返回会话ID
  8. 以后对STackOverflow的请求应具有此会话ID
  9. 不知道退出!!

此链接说明OpenID中的各种响应及其含义.因此,当您的代码作为客户端时,它可能会派上用场.

来自维基页面OpenID解释的链接

编辑:使用Tamper Data Add on for Firefox,可以构建以下事件序列.

  1. 用户向SO登录页面发送请求.在表单字段中输入openID后,生成的页面会将302重定向发送到google页面.重定向网址有很多OpenID参数(适用于Google服务器).其中之一是return_to = https://stackoverflow.com/users/authenticate/?s=some_value.
  2. 向用户显示google登录页面.在登录时,有几个302在谷歌领域重定向用户.
  3. 最后收到一个302,它将用户重定向到之前在'return_to'中指定的stackoverflow页面
  4. 在整个操作系列中,已经生成了许多必须正确存储的cookie
  5. 在访问SO页面(由谷歌302)时,SO服务器处理您的请求,并在响应标头中发送一个字段"Set-Cookie"以设置名为gauth和usr的cookie,其中包含一个值以及另一个302到stackoverflow .COM.此步骤完成您的登录
  6. 您的客户只需将cookie存储在usr中
  7. 只要您记得向任何请求发送Cookie usr,您都已登录.
  8. 您现在可以请求您的收件箱记住发送带有请求的usr cookie.

我建议你开始编写你的python客户端并仔细研究响应.在大多数情况下,它将是一系列302,用户干预最少(填写您的Google用户名和密码并允许网站页面除外).

但是为了方便起见,您可以使用浏览器登录SO,复制所有cookie值并使用urllib2并设置cookie值来发出请求.

当然,如果您在浏览器上注销,则必须再次登录并更改python程序中的cookie值.


zmo*_*zmo 6

我知道这是接近考古学,挖了两年的帖子,但我刚从经过验证的答案中写了一个新的增强版代码,所以我觉得在这里分享它可能很酷,因为这个问题/答案已经有了对我来说是一个很好的帮助来实现它.

所以,这有什么不同:

  • 它使用了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()
Run Code Online (Sandbox Code Playgroud)

代码也可以作为github gist使用

HTH


Ben*_*min 3

这个答案总结了其他人在下面所说的内容,特别是RedBaron,并添加了我用来使用 Google 帐户访问 StackOverflow 收件箱的方法。

使用Firefox的Tamper Data开发者工具并登录StackOVerflow,可以看到OpenID是这样工作的:

  1. StackOverflow 请求来自已发布数据中定义的给定服务(此处为 Google)的身份验证;
  2. Google 帐户接管并检查现有 cookie 作为身份验证证明;
  3. 如果没有找到 cookie,Google 会请求身份验证并设置 cookie;
  4. 设置 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)
Run Code Online (Sandbox Code Playgroud)