wiki身份验证流¶
警告
自从Pyramid1.0发布后,这个配方还没有收到重大的更新。从那时起,这个食谱所指的wiki教程已经收到了许多重要的更新。Pyramid1.6.1于2016年2月2日发布,并为Pyramid1.7版合并了wiki教程的主要更新。Pyramid1.7发布后,此配方将作为废弃配方删除。
本教程描述了完成 Adding authorization 来自主 Pyramid 文档的教程章节。
本文由约翰·希普曼撰写。
认证的总体流程¶
现在您已经看到了身份验证机制的所有部分,下面是一些示例,展示了它们如何一起工作。
登录失败:用户请求
/FrontPage/edit_page. 网站显示登录表单。用户进入editoras 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.里面
loginfunction, 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_inis 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 .
这个
POSToperation 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的头。