flask-roleman


Nameflask-roleman JSON
Version 1.0.3 PyPI version JSON
download
home_pageNone
SummaryFlask Extension for User Authorizations, Users can have Groups, and Each Group can have Roles, more control and easy to use.
upload_time2024-09-01 04:07:58
maintainerNone
docs_urlNone
authorMohamed El-Hasnaouy
requires_pythonNone
licenseNone
keywords flask extension roles authorization permissions security groups privileges
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
> 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"
}
        
Elapsed time: 2.70880s