Pythonized CASL library, see https://casl.js.org
Project description
PyCASL is the pythonized version of http://casl.js.org
Define abilities
Lets define Ability
for a blog website where visitors:
- can read blog posts
- can manage (i.e. do anything) own post
- cannot delete a post if it was created more than a day ago
from datetime import datetime
from casl import AbilityBuilder
def define_ability_for(user):
ability_builder = AbilityBuilder()
ability_builder.can('read', 'BlogPost')
ability_builder.can('manage', 'BlogPost', fields={'author': user.id})
ability_builder.cannot('delete', 'BlogPost', conditions=[
lambda post: post.created_at < datetime.utcnow() - datetime.timedelta(days=1)
])
return ability_builder.build()
Do you see how easily business requirements were translated into CASL's rules?
Note: you can use class instead of string as a subject type (e.g., can('read', BlogPost)
)
Check abilities
import datetime
class BlogPost(object):
def __init__(self, title, author, created_at=None):
self.title = title
self.author = author
self.created_at = created_at
if created_at is None:
self.created_at = datetime.utcnow()
user = get_loggedin_user()
ability = define_ability_for(user)
ability.can('read', 'BlogPost') # True
ability.can('read', BlogPost) # True
ability.can('manage', BlogPost('CASL', user.id)) # True
a_week_ago = datetime.utcnow() - datetime.timedelta(weeks=1)
ability.can('delete', BlogPost('CASL', user.id)) # True
ability.can('delete', BlogPost('CASL', user.id, a_week_ago)) # False
Example with flask
from casl import AbilityBuilder
from flask import _request_ctx_stack, g, request
from flask_restful import abort, fields, marshal
# Flask extension - https://flask.palletsprojects.com/en/1.1.x/extensiondev/
class FlaskAbility(object):
def __init__(self):
self.__define_abilities = None
def init_app(self, app):
app.before_request(self.init_abilities)
def define_for(self, f):
self.__define_abilities = f
def init_abilities(self):
request_context = _request_ctx_stack.top
ability_builder = AbilityBuilder()
if self.__define_abilities is not None:
self.__define_abilities(ability_builder.can, ability_builder.cannot)
casl_ability = ability_builder.build()
setattr(request_context, 'casl_ability', casl_ability)
g.ability = casl_ability
def can(self, action, subject):
def wrap(f):
def decorated(*args, **kwargs):
ctx = _request_ctx_stack.top
ability = getattr(ctx, 'casl_ability')
if not ability.can(action, subject):
abort(403, message='Access not allowed.')
return f(*args, **kwargs)
return decorated
return wrap
app = create_app()
def define_abilities(can, cannot):
user = request.user
can('read', 'BlogPost')
can('manage', 'BlogPost', fields={'author', user.id})
ability = FlaskAbility()
ability.init_app(app)
ability.define_for(define_abilities)
post_fields = {
'title': fields.String,
'author': fields.String,
'createdAt': fields.DateTime(dt_format='rfc822')
}
@app.route('/post/<string:post_id>', methods=['GET'])
@ability.can('read', 'BlogPost')
def get_blogpost(post_id):
blogpost = find_blogpost(post_id)
return marshal(blogpost, fields=post_fields), 200
@app.route('/post/<string:post_id>', methods=['PUT'])
def put_blogpost(post_id):
blogpost = find_blogpost(post_id)
if g.ability.cannot('manage', blogpost):
abort(403, message='Access not allowed')
...
update_blogpost(post_id, blogpost)
return marshal(blogpost, fields=post_fields), 200
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
PyCASL-1.0.1.tar.gz
(4.4 kB
view details)
Built Distribution
File details
Details for the file PyCASL-1.0.1.tar.gz
.
File metadata
- Download URL: PyCASL-1.0.1.tar.gz
- Upload date:
- Size: 4.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.1 importlib_metadata/4.5.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.9.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0eb196a2caadca7787fee89e64d1cff0def2491b80ad7503e92e4149c5b87c2f |
|
MD5 | df9a78ee4a54a77712e3483a414878ac |
|
BLAKE2b-256 | fbf8323c0086e7fd5f16f90106586dbecc1ea90cbb3d36ee20c2327c19ef79ee |
File details
Details for the file PyCASL-1.0.1-py3-none-any.whl
.
File metadata
- Download URL: PyCASL-1.0.1-py3-none-any.whl
- Upload date:
- Size: 4.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.1 importlib_metadata/4.5.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.9.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 91e2c5f20d5f88142b9650cf93cac34505581833ca89a107566db2fe1400164c |
|
MD5 | 968523ce230eaf4f8ff0cf041daa97cc |
|
BLAKE2b-256 | 1442a879c81460a9bfafa8813d62967d5949dbfe3181331de5efdbe3a412ca57 |