wiki身份验证流¶
警告
自从Pyramid1.0发布后,这个配方还没有收到重大的更新。从那时起,这个食谱所指的wiki教程已经收到了许多重要的更新。Pyramid1.6.1于2016年2月2日发布,并为Pyramid1.7版合并了wiki教程的主要更新。Pyramid1.7发布后,此配方将作为废弃配方删除。
本教程描述了完成 Adding authorization 来自主 Pyramid 文档的教程章节。
本文由约翰·希普曼撰写。
认证的总体流程¶
现在您已经看到了身份验证机制的所有部分,下面是一些示例,展示了它们如何一起工作。
登录失败:用户请求
/FrontPage/edit_page
. 网站显示登录表单。用户进入editor
as the login, but enters an invalid passwordbad
. 网站会重新显示登录表单,并显示消息“登录失败”。见 登录失败 .用户再次请求
/FrontPage/edit_page
. 网站显示登录表单,这次用户进入登录editor
密码editor
. 网站显示编辑表单,其中包含/FrontPage
. 用户进行了一些更改并保存它们。见 Successful login .用户再次访问
/FrontPage/edit_page
. The site goes immediately to the edit form without requesting credentials. 见 验证后重新访问 .用户单击
Logout
链接。见 注销 .
登录失败¶
当用户输入url时,进程启动。 http://localhost:6543/FrontPage/edit_page
. 假设这是对应用程序的第一个请求,页面数据库是空的,除了 Page
为首页创建的实例 initialize_sql
中的函数 models.py
.
这个过程涉及两个完整的请求/响应周期。
从首页,用户单击 Edit page . 请求是
/FrontPage/edit_page
. 可调用的视图是login.login
. 答案是login.pt
带空白字段的模板。用户输入无效的凭据并单击 Log in . 一
POST
请求发送到/FrontPage/edit_page
. 视图调用是login.login
. 答案是login.pt
显示“登录失败”消息的模板,输入字段显示其以前的值。
循环1:
在URL调度期间,路由
'/{{pagename}}/edit_page'
考虑匹配。关联视图具有view_permission='edit'
附加了权限,因此调度逻辑必须验证用户是否具有该权限,或者认为路由不匹配。所有路由匹配的上下文来自配置的根工厂,
RootFactory()
在里面models.py
. This class has an__acl__
定义所有路由的访问控制列表的属性:__acl__ = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'edit') ]
实际上,这意味着对于任何需要
edit
权限,用户必须经过身份验证,并具有group:editors
主体或路由不被认为匹配。要查找用户主体的列表,授权优先策略将检查用户是否具有
paste.auth.auth_tkt
饼干。由于用户从未访问过该站点,因此不存在此类cookie,并且该用户被视为未经身份验证。由于用户未经身份验证,因此
groupfinder
中的函数security.py
被调用None
作为其userid
争论。函数返回一个空的主体列表。因为该列表不包含
group:editors
校长'/{{pagename}}/edit_page'
路线edit
权限失败,路由不匹配。因为没有匹配的路由, forbidden view 调用callable:
login
模块中的功能login.py
.里面
login
function, the value oflogin_url
是http://localhost:6543/login
以及referrer
是http://localhost:6543/FrontPage/edit_page
.因为
request.params
没有键'came_from'
变量came_from
也设置为http://localhost:6543/FrontPage/edit_page
. 变量message
,login
和password
设置为空字符串。因为
request.params
没有键'form.submitted'
, thelogin
函数返回此字典:{'message': '', 'url':'http://localhost:6543/login', 'came_from':'http://localhost:6543/FrontPage/edit_page', 'login':'', 'password':''}
此字典用于呈现
login.pt
模板。在形式上,action
属性是http://localhost:6543/login
以及came_from
在该表单中作为隐藏字段包含在模板的该行中::<input type="hidden" name="came_from" value="${came_from}"/>
循环2:
用户输入不正确的凭据并单击 Log in 按钮,用于
POST
请求到URLhttp://localhost:6543/login
. 的名字 Log in 此表单中的按钮是form.submitted
.有图案的路线
'/login'
与此URL匹配,因此控件再次传递给login
查看可调用。这个
login_url
和referrer
这次有相同的价值(http://localhost:6543/login
如此多变referrer
设置为'/'
.自从
request.params
有键'form.submitted'
的价值观login
和password
检索自request.params
.因为登录名和密码与
USERS
词典在security.py
变量message
设置为'Failed login'
.View Callable返回此字典:
{'message':'Failed login', 'url':'http://localhost:6543/login', 'came_from':'/', 'login':'editor', 'password':'bad'}
这个
login.pt
使用这些值呈现模板。
Successful login¶
在此方案中,用户再次请求URL /FrontPage/edit_page
.
这个过程包括四个完整的请求/响应周期。
用户点击 Edit page . 可调用的视图是
login.login
. 响应是模板login.pt
,所有字段为空。The user enters valid credentials and clicks Log in . 可调用的视图是
login.login
. 响应是重定向到/FrontPage/edit_page
.可调用的视图是
views.edit_page
. The response renders templateedit.pt
,显示当前页面内容。The user edits the content and clicks Save . 可调用的视图是
views.edit_page
. 响应是重定向到/FrontPage
.
执行收益 登录失败 ,直到密码 editor
与中的值成功匹配 USERS
字典。
循环2:
内
login.login
视图可调用,值login_url
是http://localhost:6543/login
以及referrer
是'/'
和came_from
是http://localhost:6543/FrontPage/edit_page
执行此块时:if USERS.get(login) == password: headers = remember(request, login) return HTTPFound(location=came_from, headers=headers)
因为这次密码匹配,
pyramid.security.remember
返回将设置paste.auth.auth_tkt
用户浏览器中用于登录的身份验证cookie'editor'
.这个
HTTPFound
异常返回将浏览器重定向到的响应http://localhost:6543/FrontPage/edit_page
包括设置身份验证cookie的头。
循环3:
路由模式
'/{{pagename}}/edit_page'
匹配此URL,但相应的视图受'edit'
许可。因为用户现在有一个身份验证cookie将其登录名定义为
'editor'
, thegroupfinder
以该值作为函数的userid
争论。这个
groupfinder
函数返回列表['group:editors']
. 这满足访问控制条目(Allow, 'group:editors', 'edit')
, which grants theedit
许可。因此,此路由匹配,并且控制传递到视图可调用edit_page
.内
edit_page
,name
设置为'FrontPage'
,页面名称来自request.matchdict['pagename']
和page
设置为的实例models.Page
它包含了FrontPage
.因为这个请求不是来自表单,
request.params
没有密钥'form.submitted'
.这个
edit_page
函数调用pyramid.security.authenticated_userid()
logged_in
is set to the userid'editor'
.这个
edit_page
函数返回此字典:{'page':page, 'logged_in':'editor', 'save_url':'http://localhost:6543/FrontPage/edit_page'}
模板
edit.pt
用这些值呈现。除此模板的其他功能外,这些行导致包含 Logout 链接:<span tal:condition="logged_in"> <a href="${request.application_url}/logout">Logout</a> </span>
对于示例案例,此链接将引用
http://localhost:6543/logout
.模板的这些行以窗体的形式显示当前页的内容,
action
属性是http://localhost:6543/FrontPage/edit_page
::<form action="${save_url}" method="post"> <textarea name="body" tal:content="page.data" rows="10" cols="60"/> <input type="submit" name="form.submitted" value="Save"/> </form>
循环4:
用户编辑页面内容并单击 Save .
URL
http://localhost:6543/FrontPage/edit_page
和以前一样,一直走到检查request.params
有键'form.submitted'
. 这次,在edit_page
查看可调用,执行以下行:page.data = request.params['body'] session.add(page) return HTTPFound(location = route_url('view_page', request, pagename=name))
前两行将旧页内容替换为
body
窗体中的文本区域,然后更新存储在数据库中的页。第三行导致响应,将浏览器重定向到http://localhost:6543/FrontPage
.
验证后重新访问¶
在这种情况下,用户在其浏览器中设置了一个身份验证cookie,将其登录名指定为 'editor'
. 请求的URL是 http://localhost:6543/FrontPage/edit_page
.
This process requires two request/response cycles.
用户点击 Edit page . 可调用的视图是
views.edit_page
. 反应是edit.pt
,显示当前页面内容。The user edits the content and clicks Save . 可调用的视图是
views.edit_page
. 响应是重定向到/Frontpage
.
循环1:
有图案的路线
/{{pagename}}/edit_page
与URL匹配,由于身份验证cookie,groupfinder
返回包含group:editors
校长,其中models.RootFactory.__acl__
uses to grant theedit
权限,因此此路由匹配并发送到可调用的视图views.edit_page()
.在
edit_page
,因为请求不是来自表单提交,request.params
没有键'form.submitted'
.变量
logged_in
设置为登录名'editor'
通过呼叫authenticated_userid
从身份验证cookie中提取。函数返回此字典:
{'page':page, 'save_url':'http://localhost:6543/FrontPage/edit_page', 'logged_in':'editor'}
模板
edit.pt
使用该字典中的值呈现。因为存在'logged_in'
A条目 Logout 链接出现。
循环2:
用户编辑页面内容并单击 Save .
这个
POST
operation works as in Successful login .
注销¶
This process starts with a request URL http://localhost:6543/logout
.
有图案的路线
'/logout'
matches and dispatches to the view callablelogout
在里面login.py
.呼唤
pyramid.security.forget()
返回一个头元组列表,当响应返回时,该列表将导致浏览器删除用户的身份验证cookie。View Callable返回
HTTPFound
将浏览器重定向到命名路由的异常view_wiki
,将转换为URLhttp://localhost:6543
. 它还传递删除认证cookie的头。