Python Pyramid 安全性
Pyramid的声明式安全系统确定了当前用户的身份,并验证了用户是否可以访问某些资源。安全策略可以阻止用户调用某个视图。在任何视图被调用之前,授权系统使用请求中的凭证来确定是否允许访问。
安全策略被定义为一个类,在 pyramid.security 模块中定义的以下方法的帮助下控制用户访问
- forget(request) – 该方法返回适合于 “忘记 “当前认证用户所拥有的凭证集的头元。它通常在视图函数的主体中使用。
-
remember(request, userid) – 这个方法在请求的响应中返回一连串的头图元。它们适合于 “记住 “一组凭证,如使用当前安全策略的userid。在一个视图函数的主体中,常见的用法可能是这样的。
认证用户的访问由本模块中的 Allowed 和 Denied 类的对象来控制。
为了实现身份、记忆和遗忘机制的功能,Pyramid提供了以下定义在pyramid.authentication模块中的helper类 −
- SessionAuthenticationHelper – 在会话中存储用户ID。
-
AuthTktCookieHelper – 用 “auth ticket “cookie存储用户名。
我们还可以使用 extract_http_basic_credentials() 函数来检索使用HTTP Basic Auth的用户凭证。
要从WSGI环境中的REMOTE_USER检索用户ID,可以使用 request.environ.get(‘REMOTE_USER’) 。
例子
现在让我们学习如何在以下例子的帮助下实现安全策略。这个例子的 “development.ini “如下所示
[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 --
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)
我们的软件包文件夹中的 __init__.py 文件定义了以下配置。上面定义的安全策略类通过配置器类的 set_security_policy() 方法被添加到配置中。三个路由–home、login和logout–被添加到配置中。
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中定义了与上述路线对应的三个视图。
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)
登录视图显示了登录表单。当用户输入的用户身份和密码与用户列表进行核对时,这些细节会被 “记住”。另一方面,注销视图通过 “遗忘 “释放这些细节。
主页视图显示了以下变色龙模板 – 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>
以下是变色龙模板 login.pt ,用于登录查看。
<!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的软件包文件夹中。
用下面的命令安装该软件包
Env\hello>pip3 install -e.
用 pserve 工具启动服务器。
pserve development.ini
输出
打开浏览器,访问 http://localhost:6543/ 链接 。
点击 “登录 “链接,打开登录表格—-。
主视图页面回来时,链接改为注销,因为凭证被记住了。
点击 “注销 “链接将导致忘记凭证,并将显示默认的主页。