我在webpy的开发Web服务器上使用python-openid测试OpenID身份验证。通过雅虎!和myOpenID,我一直收到消息响应服务器拒绝check_authentication 。奇怪的是,我也收到了正确的openid.identity
。
相同类型的身份验证适用于Google(@ https://www.google.com/accounts/o8/ud ...)。一方面,这让我相信我做的事情是正确的,但另一方面,这种不一致让我感到困惑。
return_to
& trust_root
都是localhost:8080,可能与它有关。
这是我用来将用户发送给Yahoo!的代码验证:
def POST(self):
post_data = web.input()
if post_data.has_key('openid_identifier'):
openid_identifier = post_data.get('openid_identifier')
c = Consumer(session, openid.store.memstore.MemoryStore())
auth = c.begin(openid_identifier)
auth_url = auth.redirectURL('http://localhost:8080', return_to='http://localhost:8080/authenticate')
raise web.seeother(auth_url)
return post_data
在这种情况下, auth_url
设置为(格式化以便于阅读):
https://open.login.yahooapis.com/openid/op/auth?
openid.assoc_handle=cYSO3wJSjQa3ewmRpaQz3YodzqjosP1ta.4TVzumqlLpAFM7oWci6K9bMKG4uuqZ.5m.fY7Wp8BWfQ1eR_soHWpJ6gCsKtxi_7Bqi22T5RUcMIuQBVjpGFSjc_kRY2k-&
openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&
openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&
openid.mode=checkid_setup&
openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A8080&
openid.return_to=http%3A%2F%2Flocalhost%3A8080%2Fauthenticate%3Fjanrain_nonce%3D2010-10-08T02%253A56%253A04ZrxAI
这是处理程序在返回URL处的样子:
def GET(self):
data = web.input()
c = Consumer(session, openid.store.memstore.MemoryStore())
result = c.complete(dict(data), current_url='http://localhost:8080/authenticate')
if result.status == SUCCESS:
openid_identity = data.get('openid.identity')
...
render = web.template.render('templates/', base='layout')
return render.error(...)
result
设置为<openid.consumer.consumer.FailureResponse id=None message='Server denied check_authentication'>
,data
(返回时的查询参数)设置如下:
<Storage {'openid.op_endpoint': u'https://open.login.yahooapis.com/openid/op/auth',
'openid.sig': u'yCHffpHs2Whtw9p1gPzC+ToQJ0k=',
'openid.ns': u'http://specs.openid.net/auth/2.0',
'janrain_nonce': u'2010-10-08T02:56:04ZrxAIWh',
'openid.return_to': u'http://localhost:8080/authenticate?janrain_nonce=2010-10-08T02%3A56%3A04ZrxAIWh',
'openid.pape.auth_level.nist': u'0',
'openid.claimed_id': u'https://me.yahoo.com/a/d3eEQZAWydfmtDwaGB2vBEVU4vIMLsez#1ac56',
'openid.mode': u'id_res',
'openid.realm': u'http://localhost:8080',
'openid.response_nonce': u'2010-10-08T02:55:52ZRLNmEd7aWiaGWjHfhqEQs2Fxj3.nXdwciA--',
'openid.signed': u'assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed,pape.auth_level.nist',
'openid.identity': u'https://me.yahoo.com/a/d3eEQZAWydfmtDwaGB2vBEVU4vIMLsez',
'openid.assoc_handle': u'cYSO3wJSjQa3ewmRpaQz3YodzqjosP1ta.4TVzumqlLpAFM7oWci6K9bMKG4uuqZ.5m.fY7Wp8BWfQ1eR_soHWpJ6gCsKtxi_7Bqi22T5RUcMIuQBVjpGFSjc_kRY2k-'}>
这肯定不像是对我的失败回应。请注意openid.identity
已设置。是的,这是我在雅虎上的OpenID身份!
我不知道从哪里拿这个。有任何建议吗?
答案 0 :(得分:3)
消费者需要数据存储来维护发现和身份验证之间的状态。我正在使用的商店openid.store.memstore.MemoryStore()
实际上并没有在请求之间保持状态。它只维持一个进程中的状态 - 正如你对“内存”(duh)所期望的那样。必须改变的是在GET和POST处理程序中创建消费者。
这是创建消费者的错误方法:
# BAD: MemoryStore() has a short memory -- within the process only
c = Consumer(session, openid.store.memstore.MemoryStore())
这是创建消费者的正确方法:
# GOOD: MySQL has a long memory -- across processes
db = web.database(dbn='mysql', db='somedb', user='someuser', pw='')
conn = db._db_cursor().connection
cstore = sqlstore.MySQLStore(conn, 'openid_associations', 'openid_nonces')
c = Consumer(session, cstore)
我想有必要记住你的句柄和nonce。我一定是被困在这里10个小时,所以我希望这有助于下一个人(或加仑)避免做同样的事情。
这将是我赢得的第一笔赏金 - 我自己。活泉!
分手注意事项:这假设您在数据库中设置了OpenID表,在MySQL中应该如下所示:
create table openid_nonces (
server_url blob not null,
timestamp integer not null,
salt char(40) not null,
primary key (server_url(255), timestamp, salt)
) engine=InnoDB;
create table openid_associations (
server_url blob not null,
handle varchar(255) not null,
secret blob not null,
issued integer not null,
lifetime integer not null,
assoc_type varchar(64) not null,
primary key (server_url(255), handle)
) engine=InnoDB;
检查the documentation的openid.store.sqlstore部分,了解特定商店的相关SQL语句。