> This Software is in **Beta Version**, Please place an issue or contact me if you found a Bug !
# Flask-Roleman
**flask-roleman** is a flask extension for User Authorizations, Users can have Groups,
and Each Group can have Roles, you can define your Groups Model and Roles Model, as well as Users Model.
### About
- **Dependencies**: `flask` `flask-login`, `flask-sqlalchemy`
- **License**: Open Source Under **GNU GPL v2**
- **Author**: Mohamed El-Hasnaouy `codeberg.org/elhasnaouymed`
## Live Example
[**Jump to live example**](#the-live-example)
## Install
#### Using PIP
You can install **flask-roleman** using **pip**:
```shell
pip install flask-roleman
```
#### From source
Or you can download & compile & install it from source:
1. `git clone https://codeberg.org/Elhasnaouymed/flask-roleman.git`
2. `cd flask-roleman`
3. `python setup.py sdist`
4. `pip install dist/flask-roleman-*.tar.gz`
> Note: on most GNU/Linux distributions, You can install **only** inside a Virtual Environment (see [PEP 0668](https://peps.python.org/pep-0668/))
## Initialization
As most Extensions of Flask, you first import and create the Main Instance, then you can **Initialize** it in place
or after:
```python
...
db = SQLAlchemy()
roleman = RoleMan()
...
roleman.init_db(db, create_secondaries=True)
...
```
But before initialization, you **must** define the three models to inherit from their mixing,
as shown in the [next section](#usage).
also you should initialize before `db.init_app()` to allow secondary tables to be created.
### Mixing
To use **RoleMan** in your project, you need to have:
- **User Model** that inherits from `flask_roleman.UserModelMixing`.
- **Group Model** that inherits from `flask_roleman.GroupModelMixing`.
- **Role Model** that inherits from `flask_roleman.RoleModelMixing`.
> Group Model must have:
> - A String column `name`.
> - `users`: *many-to-many* relationship to the Users model, with `secondary=RoleMan.SECONDARY_USER_GROUP_TABLE_NAME` and `backref="groups"`.
> - `roles`: *many-to-many* relationship to the Roles model, with `secondary=RoleMan.SECONDARY_GROUP_ROLE_TABLE_NAME` and `backref="groups"`.
> Role Model must have:
> - A String column `name`.
### Minimal Example
Minimal Example of defining the three necessary Models with their Inheritance:
```python
from flask_roleman import RoleMan, UserModelMixing, GroupModelMixing, RoleModelMixing
class User(db.Model, UserModelMixing):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String, nullable=False, unique=True)
password = db.Column(db.String, nullable=False)
...
class Group(db.Model, GroupModelMixing):
__tablename__ = 'group'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, unique=True)
users = db.relationship('User', secondary=RoleMan.SECONDARY_USER_GROUP_TABLE_NAME, backref="groups")
roles = db.relationship('Role', secondary=RoleMan.SECONDARY_GROUP_ROLE_TABLE_NAME, backref="groups")
...
class Role(db.Model, RoleModelMixing):
__tablename__ = 'role'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, unique=True)
...
```
# Usage
There are two ways to use this tool, [One](#static-authorizing) by decorating the route you want to protect,
[Two](#dynamic-authorizing) is by using `.has_roles()` method over a User or a Group
Both methods take variable length argument `*roles=Tuple[Union[List[str], str]]`, you can pass a list of roles like `['admin', 'manager', 'chief']`
or just a role name as string like `'admin'`
> * by passing a list, the User must have at least one of the Roles
> * by passing a string, the User must have that Role
>
> In other words: the program performs *AND* operator over the method arguments, and *OR* over the list values.
> **Notes**
>> You should assign Roles to Groups, and Groups to the Users.
>
>> The user get Authorized only if he has at least one of the Requested roles bound to one of his Groups.
## Static Authorizing
Whenever you want to **Require a role** from User, use this Decorator:
```python
from flask_roleman import roles_required
@app.route('/admin')
@roles_required('admin')
def admin_page():
...
return render_template('admin.html')
```
## Dynamic Authorizing
Or you can check dynamically using `current_user.has_roles`:
```python
from flask_login import current_user
from flask import abort
@app.route('/admin')
def admin_page():
if not current_user.has_roles('admin'):
return abort(401)
return render_template('admin.html')
```
# The Live Example
**In This example, the user will always get 401 error when accessing `/admin`,
until he logs in with a user that has the 'admin' role in one of his groups**
```python
from flask import Flask
from flask_login import LoginManager
from flask_roleman import RoleMan, UserModelMixing, GroupModelMixing, RoleModelMixing, roles_required
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SECRET_KEY'] = '5d19362626f3290221a2b37f0a5038d07e5aa0e18a9967ffcbedc69eaee4cce9'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.db'
db = SQLAlchemy()
login_manager = LoginManager(app)
@login_manager.user_loader
def user_loader(id: int):
return User.query.get(id)
class User(db.Model, UserModelMixing):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String, nullable=False, unique=True)
password = db.Column(db.String, nullable=False)
class Group(db.Model, GroupModelMixing):
__tablename__ = 'group'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, unique=True)
users = db.relationship('User', secondary=RoleMan.SECONDARY_USER_GROUP_TABLE_NAME, backref="groups")
roles = db.relationship('Role', secondary=RoleMan.SECONDARY_GROUP_ROLE_TABLE_NAME, backref="groups")
class Role(db.Model, RoleModelMixing):
__tablename__ = 'role'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, unique=True)
@app.route('/')
def home():
return 'Hello World! from Home'
@app.route('/admin')
@roles_required('admin')
def admin():
return 'Admin Page !!!'
if __name__ == '__main__':
app.run(debug=True)
```
Raw data
{
"_id": null,
"home_page": null,
"name": "flask-roleman",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "flask, extension, roles, authorization, permissions, security, groups, privileges",
"author": "Mohamed El-Hasnaouy",
"author_email": "<elhasnaouymed@proton.me>",
"download_url": "https://files.pythonhosted.org/packages/09/57/a27ce246bf5a99eff187c72745d3455c6bd6139d5424668d343082d297a3/flask_roleman-1.0.3.tar.gz",
"platform": null,
"description": "\n> This Software is in **Beta Version**, Please place an issue or contact me if you found a Bug !\n\n# Flask-Roleman\n\n**flask-roleman** is a flask extension for User Authorizations, Users can have Groups, \nand Each Group can have Roles, you can define your Groups Model and Roles Model, as well as Users Model.\n\n### About\n\n- **Dependencies**: `flask` `flask-login`, `flask-sqlalchemy`\n- **License**: Open Source Under **GNU GPL v2**\n- **Author**: Mohamed El-Hasnaouy `codeberg.org/elhasnaouymed`\n\n## Live Example\n\n[**Jump to live example**](#the-live-example)\n\n## Install\n\n#### Using PIP\n\nYou can install **flask-roleman** using **pip**:\n\n```shell\npip install flask-roleman\n```\n\n#### From source\n\nOr you can download & compile & install it from source:\n\n1. `git clone https://codeberg.org/Elhasnaouymed/flask-roleman.git`\n2. `cd flask-roleman`\n3. `python setup.py sdist`\n4. `pip install dist/flask-roleman-*.tar.gz`\n\n> Note: on most GNU/Linux distributions, You can install **only** inside a Virtual Environment (see [PEP 0668](https://peps.python.org/pep-0668/))\n\n## Initialization\n\nAs most Extensions of Flask, you first import and create the Main Instance, then you can **Initialize** it in place\nor after:\n\n```python\n...\n\ndb = SQLAlchemy()\nroleman = RoleMan()\n\n...\n\nroleman.init_db(db, create_secondaries=True)\n\n...\n```\n\nBut before initialization, you **must** define the three models to inherit from their mixing,\nas shown in the [next section](#usage).\n\nalso you should initialize before `db.init_app()` to allow secondary tables to be created.\n\n### Mixing\n\nTo use **RoleMan** in your project, you need to have:\n - **User Model** that inherits from `flask_roleman.UserModelMixing`.\n - **Group Model** that inherits from `flask_roleman.GroupModelMixing`.\n - **Role Model** that inherits from `flask_roleman.RoleModelMixing`.\n\n> Group Model must have:\n> - A String column `name`.\n> - `users`: *many-to-many* relationship to the Users model, with `secondary=RoleMan.SECONDARY_USER_GROUP_TABLE_NAME` and `backref=\"groups\"`.\n> - `roles`: *many-to-many* relationship to the Roles model, with `secondary=RoleMan.SECONDARY_GROUP_ROLE_TABLE_NAME` and `backref=\"groups\"`.\n\n> Role Model must have:\n> - A String column `name`.\n\n### Minimal Example\nMinimal Example of defining the three necessary Models with their Inheritance:\n\n```python\nfrom flask_roleman import RoleMan, UserModelMixing, GroupModelMixing, RoleModelMixing\n\nclass User(db.Model, UserModelMixing):\n __tablename__ = 'user'\n id = db.Column(db.Integer, primary_key=True)\n email = db.Column(db.String, nullable=False, unique=True)\n password = db.Column(db.String, nullable=False)\n ...\n\nclass Group(db.Model, GroupModelMixing):\n __tablename__ = 'group'\n id = db.Column(db.Integer, primary_key=True)\n name = db.Column(db.String, nullable=False, unique=True)\n users = db.relationship('User', secondary=RoleMan.SECONDARY_USER_GROUP_TABLE_NAME, backref=\"groups\")\n roles = db.relationship('Role', secondary=RoleMan.SECONDARY_GROUP_ROLE_TABLE_NAME, backref=\"groups\")\n ...\n \nclass Role(db.Model, RoleModelMixing):\n __tablename__ = 'role'\n id = db.Column(db.Integer, primary_key=True)\n name = db.Column(db.String, nullable=False, unique=True)\n ...\n```\n\n# Usage\n\nThere are two ways to use this tool, [One](#static-authorizing) by decorating the route you want to protect, \n[Two](#dynamic-authorizing) is by using `.has_roles()` method over a User or a Group\n\nBoth methods take variable length argument `*roles=Tuple[Union[List[str], str]]`, you can pass a list of roles like `['admin', 'manager', 'chief']`\nor just a role name as string like `'admin'`\n\n> * by passing a list, the User must have at least one of the Roles\n> * by passing a string, the User must have that Role\n> \n> In other words: the program performs *AND* operator over the method arguments, and *OR* over the list values.\n\n\n> **Notes**\n>> You should assign Roles to Groups, and Groups to the Users.\n> \n>> The user get Authorized only if he has at least one of the Requested roles bound to one of his Groups. \n\n## Static Authorizing\n\nWhenever you want to **Require a role** from User, use this Decorator:\n\n```python\nfrom flask_roleman import roles_required\n\n@app.route('/admin')\n@roles_required('admin')\ndef admin_page():\n ...\n return render_template('admin.html')\n```\n\n## Dynamic Authorizing\n\nOr you can check dynamically using `current_user.has_roles`:\n\n```python\nfrom flask_login import current_user\nfrom flask import abort\n\n@app.route('/admin')\ndef admin_page():\n if not current_user.has_roles('admin'):\n return abort(401)\n return render_template('admin.html')\n```\n\n\n# The Live Example\n\n**In This example, the user will always get 401 error when accessing `/admin`,\nuntil he logs in with a user that has the 'admin' role in one of his groups**\n\n```python\nfrom flask import Flask\nfrom flask_login import LoginManager\nfrom flask_roleman import RoleMan, UserModelMixing, GroupModelMixing, RoleModelMixing, roles_required\nfrom flask_sqlalchemy import SQLAlchemy\n\napp = Flask(__name__)\napp.config['SECRET_KEY'] = '5d19362626f3290221a2b37f0a5038d07e5aa0e18a9967ffcbedc69eaee4cce9'\napp.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.db'\ndb = SQLAlchemy()\nlogin_manager = LoginManager(app)\n\n\n@login_manager.user_loader\ndef user_loader(id: int):\n return User.query.get(id)\n\n\nclass User(db.Model, UserModelMixing):\n __tablename__ = 'user'\n id = db.Column(db.Integer, primary_key=True)\n email = db.Column(db.String, nullable=False, unique=True)\n password = db.Column(db.String, nullable=False)\n\n\nclass Group(db.Model, GroupModelMixing):\n __tablename__ = 'group'\n id = db.Column(db.Integer, primary_key=True)\n name = db.Column(db.String, nullable=False, unique=True)\n users = db.relationship('User', secondary=RoleMan.SECONDARY_USER_GROUP_TABLE_NAME, backref=\"groups\")\n roles = db.relationship('Role', secondary=RoleMan.SECONDARY_GROUP_ROLE_TABLE_NAME, backref=\"groups\")\n\n\nclass Role(db.Model, RoleModelMixing):\n __tablename__ = 'role'\n id = db.Column(db.Integer, primary_key=True)\n name = db.Column(db.String, nullable=False, unique=True)\n\n\n@app.route('/')\ndef home():\n return 'Hello World! from Home'\n\n@app.route('/admin')\n@roles_required('admin')\ndef admin():\n return 'Admin Page !!!'\n\n\nif __name__ == '__main__':\n app.run(debug=True)\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "Flask Extension for User Authorizations, Users can have Groups, and Each Group can have Roles, more control and easy to use.",
"version": "1.0.3",
"project_urls": null,
"split_keywords": [
"flask",
" extension",
" roles",
" authorization",
" permissions",
" security",
" groups",
" privileges"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0fbc5ab14931786b964ce3e9b5cd2c358d2fe19881d5f48b47936aa43e6319cc",
"md5": "954c16e286615e64e11fa92b2f4b8a78",
"sha256": "0078fa2619533fc94addde3b2452fcf358228d0c7d8bd33309231da76ed5c176"
},
"downloads": -1,
"filename": "flask_roleman-1.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "954c16e286615e64e11fa92b2f4b8a78",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 6384,
"upload_time": "2024-09-01T04:07:56",
"upload_time_iso_8601": "2024-09-01T04:07:56.181402Z",
"url": "https://files.pythonhosted.org/packages/0f/bc/5ab14931786b964ce3e9b5cd2c358d2fe19881d5f48b47936aa43e6319cc/flask_roleman-1.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0957a27ce246bf5a99eff187c72745d3455c6bd6139d5424668d343082d297a3",
"md5": "bd774126b998b03d2e5b1bbf47130265",
"sha256": "1f9b84d8e2919aa2161d7d1b88f4339eb2c813125374b1ed856e6c8e9bb8e77b"
},
"downloads": -1,
"filename": "flask_roleman-1.0.3.tar.gz",
"has_sig": false,
"md5_digest": "bd774126b998b03d2e5b1bbf47130265",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 5655,
"upload_time": "2024-09-01T04:07:58",
"upload_time_iso_8601": "2024-09-01T04:07:58.427601Z",
"url": "https://files.pythonhosted.org/packages/09/57/a27ce246bf5a99eff187c72745d3455c6bd6139d5424668d343082d297a3/flask_roleman-1.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-01 04:07:58",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "flask-roleman"
}