AMSDAL Auth Plugin¶
AMSDAL Auth Plugin provides the ability to add authorization mechanism to your AMSDAL Rest API, and also manage users and permissions.
To enable this plugin, add amsdal.contrib.auth.app.AuthAppConfig
value to AMSDAL_CONTRIBS environment variable (enabled by default).
Models¶
Plugin provides the following models:
User¶
User model is used to store user credentials (email and password) and permissions.
Fields:
email
- user emailpassword
- hash of user passwordpermissions
- list of references toPermission
model
Permission¶
Permission model is used to store existing permissions to be used in your application.
Fields:
model
- string value of model name, or any other string value to be used as permission name. Can be*
to allow access to all models.action
- string value of action name (e.g.create
,read
,update
,delete
). Can be*
to allow access to all actions.
When you create permission for a specific model with one of standard actions, it will be used as required permission for this action on this model.
For example, if you create permission with model
=User
and action
=create
, users without this permission will not be able to create new users.
To remove this restriction, you need to delete this permission.
LoginSession¶
LoginSession model is used to store information about user login sessions. To authenticate user, you need to create new LoginSession object with user's email and password.
If user with such credentials exists, new LoginSession object will be created and returned to you. This object contains token
field, which you need to use in
Authorization header in all your requests to AMSDAL Rest API.
Fields:
email
- user emailpassword
- hash of user passwordtoken
- token to be used in Authorization header in all your requests to AMSDAL Rest API
More on permissions¶
You can create permissions for any model and action, even if this model or action does not exist in your application.
Here are some examples of what access user has depending on permissions:
User permissions | Permissions in DB | User access |
---|---|---|
No permissions | Model:create |
Can read, update and delete but not create Model objects |
No permissions | Model:* |
Full access to Model objects (asterisk permissions are ignored) |
Model:create |
Model:create |
Full access to Model objects |
Model:create |
Model:create , Model:read |
Can create, update and delete but not read Model objects |
*:* |
Model:create |
Full access to Model objects |
Model:* |
Model:create |
Full access to Model objects |
Lifecycles¶
Event | Name | Description |
---|---|---|
ON_SERVER_STARTUP | CheckAndCreateSuperUserConsumer | Checks if admin user exists and creates it if not |
ON_AUTHENTICATE | AuthenticateUserConsumer | Decodes JWT token and mixes user into authentication_info |
ON_PERMISSION_CHECK | CheckPermissionConsumer | Checks if user has required permission to perform action on model |
Environment variables¶
AMSDAL_ADMIN_USER_EMAIL
- email of admin user to be created on application startAMSDAL_ADMIN_USER_PASSWORD
- password of admin user to be created on application startAMSDAL_AUTH_JWT_KEY
- key to be used to sign JWT tokens during user authenticationAMSDAL_REQUIRE_DEFAULT_AUTHORIZATION
- whether to require permissions for the model by default.true
by default
Usage¶
To create a permission, you can use JSON fixtures. For example, here is a fixture that
creates permissions for User
model to allow creating, updating and deleting new users. After adding this fixture to
your application, users without these permissions will not be able to create, update or delete users, but will
be able to read them.
{
"Permission": [
{
"external_id": "user_create",
"model": "User",
"action": "create"
},
{
"external_id": "user_update",
"model": "User",
"action": "update"
},
{
"external_id": "user_delete",
"model": "User",
"action": "delete"
}
]
}
Custom permission checks¶
You can create a custom permission checks for class or specific objects actions by adding modifiers to the class.
To modify the check for class actions (list objects or create a new object), you need to add has_permission
class
method, and write your custom logic there. This method should return True
if user has has permission, and False
otherwise.
For object actions (read, update, delete), you need to add has_object_permission
method.
For example, here is two methods that allow only users with email admin@example.com
to create, update or delete objects,
authorized users to read objects, and deny any access to unauthorized users:
from typing import Any
from amsdal_server.apps.common.errors import AmsdalPermissionError
@classmethod
def has_permission(cls, user: Any, action: str) -> bool:
if not user:
raise AmsdalPermissionError(access_type=action, class_name=cls.__name__)
if (
action == 'create'
and getattr(user, 'email', None) != 'admin@example.com'
):
return False
return True
def has_object_permission(self, user: Any, action: str) -> bool:
if not user:
raise AmsdalPermissionError(
access_type=action,
class_name=self.__class__.__name__,
)
if (
action in ['update', 'delete']
and getattr(user, 'email', None) != 'admin@example.com'
):
return False
return True
Transactions¶
There is no way to add automatic permissions check for transactions, but you can create and user decorators for that.
There is already require_auth
decorator to check if user is authenticated, you can use it as an example to create
your own decorators.
Here is an example of usage of require_auth
decorator:
from amsdal.contrib.auth.decorators import require_auth
from amsdal_data.transactions import transaction
@require_auth
@transaction
def transaction_require_auth(dummy_int: int) -> int:
return dummy_int