【Flask】Flask-Principal介绍译文

来源:互联网 发布:淘宝极有家装修日记 编辑:程序博客网 时间:2024/05/16 18:36

介绍

Flask-Principal提供了非常松散的框架,以绑定两种类型服务机制,它们通常位于一个web应用程序的不同部分。

  1. 权限认证机制
  2. 用户信息管理机制

例如,一个权限认证机制采用 OAuth,使用Flask-OAuth,用户信息存储在关系数据库中。框架使用signal消息作为应用接口(松耦合)。

框架主要部分包含身份(Identity),需求(Needs),权限(Permission),和包含身份信息上下文环境(IdentityContext)

  1. Identity代表用户,并为每个请求(例如会话)保存/加载不同位置。对系统来说,身份是用户的化身。它包含了用户的访问权限。
    2.Need是最小原子的访问控制,并代表一个特定参数的情况。例如“管理角色”,“可以编辑博客”。
  2. Permission是任何时候访问资源,都应该出现的功能。
  3. IdentityContext是某种身份的背景下针对特定的许可。它可以用于作为一个上下文管理器(context manager)或装饰(decorator)。

这里写图片描述

保护访问的资源

对用户(不是身份验证机制)进行访问限制很容易使用,可以作为装饰或上下文管理器,下面是示例。

from flask import Flask, Responsefrom flask.ext.principal import Principal, Permission, RoleNeedapp = Flask(__name__)# load the extensionprincipals = Principal(app)# Create a permission with a single Need, in this case a RoleNeed.admin_permission = Permission(RoleNeed('admin'))# protect a view with a principal for that need@app.route('/admin')@admin_permission.require()def do_admin_index():    return Response('Only if you are an admin')# this time protect with a context manager@app.route('/articles')def do_articles():    with admin_permission.require():        return Response('Only if you are admin')

权限认证机制

身份验证机制应该使用identity-changed信号表明请求已经被验证过。例如,下面的代码是一个例子,如何将流行的Flask-Login与Flask-Principal扩展:

from flask import Flask, current_app, request, sessionfrom flask.ext.login import LoginManager, login_user, logout_user, \     login_required, current_userfrom flask.ext.wtf import Form, TextField, PasswordField, Required, Emailfrom flask.ext.principal import Principal, Identity, AnonymousIdentity, \     identity_changedapp = Flask(__name__)Principal(app)login_manager = LoginManager(app)@login_manager.user_loaderdef load_user(userid):    # Return an instance of the User model    return datastore.find_user(id=userid)class LoginForm(Form):    email = TextField()    password = PasswordField()@app.route('/login', methods=['GET', 'POST'])def login():    # A hypothetical login form that uses Flask-WTF    form = LoginForm()    # Validate form input    if form.validate_on_submit():        # Retrieve the user from the hypothetical datastore        user = datastore.find_user(email=form.email.data)        # Compare passwords (use password hashing production)        if form.password.data == user.password:            # Keep the user info in the session using Flask-Login            login_user(user)            # Tell Flask-Principal the identity changed            identity_changed.send(current_app._get_current_object(),                                  identity=Identity(user.id))            return redirect(request.args.get('next') or '/')    return render_template('login.html', form=form)@app.route('/logout')@login_requireddef logout():    # Remove the user information from the session    logout_user()    # Remove session keys set by Flask-Principal    for key in ('identity.name', 'identity.auth_type'):        session.pop(key, None)    # Tell Flask-Principal the user is anonymous    identity_changed.send(current_app._get_current_object(),                          identity=AnonymousIdentity())    return redirect(request.args.get('next') or '/')

用户信息管理机制

用户信息管理机制应该接收identity-loaded信号(signal),对身份实例添加任何信息,比如角色(roles)。下面是另一个使用Flask-Login和连接上面代码的例子。它是一个可使用的基于角色的权限方案。

from flask.ext.login import current_userfrom flask.ext.principal import identity_loaded, RoleNeed, UserNeed@identity_loaded.connect_via(app)def on_identity_loaded(sender, identity):    # Set the identity user object    identity.user = current_user    # Add the UserNeed to the identity    if hasattr(current_user, 'id'):        identity.provides.add(UserNeed(current_user.id))    # Assuming the User model has a list of roles, update the    # identity with the roles that the user provides    if hasattr(current_user, 'roles'):        for role in current_user.roles:            identity.provides.add(RoleNeed(role.name))

你可以把上面代码放在create_app里。

细粒度的资源保护

现在比如,你仅仅想作者可以发布和编辑文章,这个需要创建NeedPermission对象,并对identity_loaded信号处理程序添加更多的逻辑。例如:

from collections import namedtuplefrom functools import partialfrom flask.ext.login import current_userfrom flask.ext.principal import identity_loaded, Permission, RoleNeed, \     UserNeedBlogPostNeed = namedtuple('blog_post', ['method', 'value'])EditBlogPostNeed = partial(BlogPostNeed, 'edit')class EditBlogPostPermission(Permission):    def __init__(self, post_id):        need = EditBlogPostNeed(unicode(post_id))        super(EditBlogPostPermission, self).__init__(need)@identity_loaded.connect_via(app)def on_identity_loaded(sender, identity):    # Set the identity user object    identity.user = current_user    # Add the UserNeed to the identity    if hasattr(current_user, 'id'):        identity.provides.add(UserNeed(current_user.id))    # Assuming the User model has a list of roles, update the    # identity with the roles that the user provides    if hasattr(current_user, 'roles'):        for role in current_user.roles:            identity.provides.add(RoleNeed(role.name))    # Assuming the User model has a list of posts the user    # has authored, add the needs to the identity    if hasattr(current_user, 'posts'):        for post in current_user.posts:            identity.provides.add(EditBlogPostNeed(unicode(post.id)))

下一步将保护endpoint,允许用户编辑文章。这是通过资源的ID(post_id)创建一个许可对象实例:

@app.route('/posts/<post_id>', methods=['PUT', 'PATCH'])def edit_post(post_id):    permission = EditBlogPostPermission(post_id)    if permission.can():        # Save the edits ...        return render_template('edit_post.html')    abort(403)  # HTTP Forbidden

来源:http://pythonhosted.org/Flask-Principal/

0 0
原创粉丝点击