Python Pyramid 简明教程
Python Pyramid - Security
Pyramid 的声明式安全系统确定当前用户的身份,并验证用户是否有权访问某些资源。安全策略可以防止用户调用视图。在调用任何视图之前,授权系统使用请求中的凭证来确定是否允许访问。
Pyramid’s declarative security system determines the identity of the current user and verifies if the user has access to certain resources. The security policy can prevent the user from invoking a view. Before any view is invoked, the authorization system uses the credentials in the request to determine if access will be allowed.
安全策略定义为一个类,该类借助 pyramid.security 模块中定义的以下方法控制用户访问:
The security policy is defined as a class that controls the user access with the help of following methods defined in pyramid.security module −
-
forget(request) − This method returns header tuples suitable for 'forgetting' the set of credentials possessed by the currently authenticated user. It is generally used within the body of a view function.
-
remember(request, userid) − This method returns a sequence of header tuples on the request’s response. They are suitable for 'remembering' a set of credentials such as userid using the current security policy. Common usage might look like so within the body of a view function.
此模块中 Allowed 和 Denied 类对象控制经过验证用户的访问。
The authenticated user’s access is controlled by the objects of Allowed and Denied classes in this module.
要实现身份的功能,记住和忘记机制,Pyramid 提供了以下 helper 类,这些类定义在 pyramid.authentication 模块中:
To implement the functionality of identity, remember and forget mechanism, Pyramid provides the following helper classes defined in the pyramid.authentication module −
-
SessionAuthenticationHelper − Store the userid in the session.
-
AuthTktCookieHelper − Store the userid with an "auth ticket" cookie.
我们还可以使用 extract_http_basic_credentials() 函数使用 HTTP Basic Auth 检索用户凭证。
We can also use extract_http_basic_credentials() function to retrieve user credentials using HTTP Basic Auth.
要从 WSGI 环境中的 REMOTE_USER 中检索用户 ID,可以使用 request.environ.get('REMOTE_USER') 。
To retrieve the userid from REMOTE_USER in the WSGI environment, the request.environ.get('REMOTE_USER') can be used.
Example
下面让我们学习如何使用以下示例实现安全策略。此示例的“development.ini”如下:
Let us now learn how to implement the security policy with the help of following example. The "development.ini" for this example is as follows −
[app:main]
use = egg:tutorial
pyramid.reload_templates = true
pyramid.includes = pyramid_debugtoolbar
hello.secret = a12b
[server:main]
use = egg:waitress#main
listen = localhost:6543
然后我们在以下 Python 代码(另存为 security.py )中编写安全策略类:
We then write the security policy class in the following Python code saved as security.py −
from pyramid.authentication import AuthTktCookieHelper
USERS = {'admin': 'admin', 'manager': 'manager'}
class SecurityPolicy:
def __init__(self, secret):
self.authtkt = AuthTktCookieHelper(secret=secret)
def identity(self, request):
identity = self.authtkt.identify(request)
if identity is not None and identity['userid'] in USERS:
return identity
def authenticated_userid(self, request):
identity = self.identity(request)
if identity is not None:
return identity['userid']
def remember(self, request, userid, **kw):
return self.authtkt.remember(request, userid, **kw)
def forget(self, request, **kw):
return self.authtkt.forget(request, **kw)
package 文件夹中的 init.py 文件定义以下配置。上面定义的安全策略类已通过 Configurator 类的 set_security_policy() 方法添加到配置中。三个路由 - home、login 和 logout - 已添加到配置中。
The init.py file in our package folder defines following configuration. The security policy class defined above is added in the configuration with set_security_policy() method of Configurator class. Three routes - home, login and logout – are added to the configuration.
from pyramid.config import Configurator
from .security import SecurityPolicy
def main(global_config, **settings):
config = Configurator(settings=settings)
config.include('pyramid_chameleon')
config.set_security_policy(
SecurityPolicy(
secret=settings['hello.secret'],
),
)
config.add_route('home', '/')
config.add_route('login', '/login')
config.add_route('logout', '/logout')
config.scan('.views')
return config.make_wsgi_app()
与上述路由相对应的三个视图已在 views.py 中定义。
Three views corresponding to the above routes are defined in views.py.
from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget
from pyramid.view import view_config, view_defaults
from .security import USERS
@view_defaults(renderer='home.pt')
class HelloViews:
def __init__(self, request):
self.request = request
self.logged_in = request.authenticated_userid
@view_config(route_name='home')
def home(self):
return {'name': 'Welcome'}
@view_config(route_name='login', renderer='login.pt')
def login(self):
request = self.request
login_url = request.route_url('login')
referrer = request.url
if referrer == login_url:
referrer = '/'
came_from = request.params.get('came_from', referrer)
message = ''
login = ''
password = ''
if 'form.submitted' in request.params:
login = request.params['login']
password = request.params['password']
pw = USERS.get(login)
if pw == password:
headers = remember(request, login)
return HTTPFound(location=came_from, headers=headers)
message = 'Failed login'
return dict(
name='Login', message=message,
url=request.application_url + '/login',
came_from=came_from,
login=login, password=password,)
@view_config(route_name='logout')
def logout(self):
request = self.request
headers = forget(request)
url = request.route_url('home')
return HTTPFound(location=url, headers=headers)
登录视图呈现登录表单。当用户输入的用户 ID 和密码与 USERS 列表进行验证时,这些详细信息将被“记住”。另一方面,注销视图通过“忘记”释放这些详细信息。
The login view renders the login form. When the user Id and password entered by the user are verified against the list of USERS, the details are 'remembered'. On the other hand, the logout view releases these details by 'forgetting'.
home 视图呈现以下 chameleon 模板 - home.pt
The home view renders the following chameleon template - home.pt
<!DOCTYPE html>
<html lang="en">
<body>
<div>
<a tal:condition="view.logged_in is None" href="${request.application_url}/login">Log In</a>
<a tal:condition="view.logged_in is not None" href="${request.application_url}/logout">Logout</a>
</div>
<h1>Hello. ${name}</h1>
</body>
</html>
以下是登录视图的 chameleon 模板 login.pt 。
Following is the chameleon template login.pt for login view.
<!DOCTYPE html>
<html lang="en">
<body>
<h1>Login</h1>
<span tal:replace="message"/>
<form action="${url}" method="post">
<input type="hidden" name="came_from" value="${came_from}"/>
<label for="login">Username</label>
<input type="text" id="login" name="login" value="${login}"/><br/>
<label for="password">Password</label>
<input type="password" id="password" name="password" value="${password}"/><br/>
<input type="submit" name="form.submitted" value="Log In"/>
</form>
</body>
</html>
development.ini 和 setup.py 位于外部项目文件夹中,而 init.py, views.py, security.py 和模板 home.pt 以及 login.pt 应保存在名为 hello 的包文件夹中。
The development.ini and setup.py are placed in the outer project folder, while, the init.py, views.py, security.py and the templates home.pt as well as login.pt should be saved under the package folder named hello.
使用以下命令安装该软件包 −
Install the package with the following command −
Env\hello>pip3 install -e.
使用 pserve 实用工具启动服务器。
Start the server with the pserve utility.
pserve development.ini
Output
打开浏览器并访问 http://localhost:6543/ 链接。
Open the browser and visit http://localhost:6543/ link.
单击“登录”链接以打开登录表单 −
Click the "Log In" link to open the login form −
home 视图页面返回,链接改为注销,因为这些凭据已被记住。
The home view page comes back with the link changed to logout as the credentials are remembered.
单击“注销”链接将导致忘记凭据,并将显示默认主页。
Clicking the "logout" link will result in forgetting the credentials and the default home page will be shown.