Authentication¶
Like SQLAdmin, Esmerald Admin does not enfoce any authentication, but provides two out-of-the-box
optional EmailAdminAuth
and UsernameAdminAuth
using the Esmerald contrib auth for
Saffier that you can use or models for Edgy.
Note
If you don't use the Esmerald models for Saffier or Edgy, you can simply ignore this and use your own implementation and follow the instructions from the SQLAdmin.
EmailAdminAuth and UsernameAdminAuth¶
These two authentication backends use the AuthenticationBackend
from SQLAdmin
and apply logins using email
or username
, your choice.
EmailAdminAuth
and UsernameAdminAuth
expect three parameters:
secret_key
- The secret to be used with your auth.auth_model
- The class object of yourUser
, usually derived from the User model for Saffier or User model for Edgy.config
- The application settings object. It can be the settings config or the applicationsettings
fromesmerald.conf
. It all depends of which one you use.
How to use¶
This is how you could use the backends in your Esmerald application. This example is very simple and it will use the settings_config from Esmerald to simplify. This is not mandatory and you can use your preferred way.
from esmerald import Esmerald, EsmeraldAPISettings, Include
from esmerald.config.jwt import JWTConfig
from esmerald.contrib.auth.saffier.base_user import AbstractUser
from saffier import Database, Registry
from esmerald_admin import Admin
from esmerald_admin.backends.saffier.email import EmailAdminAuth
database = Database("sqlite:///db.sqlite")
registry = Registry(database=database)
class AppSettings(EsmeraldAPISettings):
@property
def jwt_config(self) -> JWTConfig:
return JWTConfig(signing_key=self.secret_key)
class User(AbstractUser):
"""Inherits from the user base"""
class Meta:
registry = registry
# You can use the `settings_config` directly or ESMERALD_SETTINGS_MODULE
settings = AppSettings()
def get_application():
"""
This is optional. The function is only used for organisation purposes.
"""
app = Esmerald(
routes=[Include(namespace="linezap.urls")],
on_startup=[database.connect],
on_shutdown=[database.disconnect],
settings_config=settings,
)
# EmailAdminAuth or UsernameAdminAuth
auth_backend = EmailAdminAuth(
secret_key=settings.secret_key, auth_model=User, config=settings.jwt_config
)
Admin(app, registry.engine, authentication_backend=auth_backend)
return app
app = get_application()
from edgy import Database, Registry
from esmerald import Esmerald, EsmeraldAPISettings, Include
from esmerald.config.jwt import JWTConfig
from esmerald.contrib.auth.edgy.base_user import AbstractUser
from esmerald_admin import Admin
from esmerald_admin.backends.edgy.email import EmailAdminAuth
database = Database("sqlite:///db.sqlite")
registry = Registry(database=database)
class AppSettings(EsmeraldAPISettings):
@property
def jwt_config(self) -> JWTConfig:
return JWTConfig(signing_key=self.secret_key)
class User(AbstractUser):
"""Inherits from the user base"""
class Meta:
registry = registry
# You can use the `settings_config` directly or ESMERALD_SETTINGS_MODULE
settings = AppSettings()
def get_application():
"""
This is optional. The function is only used for organisation purposes.
"""
app = Esmerald(
routes=[Include(namespace="linezap.urls")],
on_startup=[database.connect],
on_shutdown=[database.disconnect],
settings_config=settings,
)
# EmailAdminAuth or UsernameAdminAuth
auth_backend = EmailAdminAuth(
secret_key=settings.secret_key, auth_model=User, config=settings.jwt_config
)
Admin(app, registry.engine, authentication_backend=auth_backend)
return app
app = get_application()
To use the UsernameAdminAuth
instead:
from esmerald_admin.backends.saffier.username import UsernameAdminAuth
from esmerald_admin.backends.edgy.username import UsernameAdminAuth
The User
model as you can notice, is the one that derived from Esmerald and the reason for this
is because the Esmerald models come with a lot of functionality already built-in such as password
hashing and checks for passwords and therefore, makes it easier to use it.
Tip
SQLAdmin has clear instructions in case you want to build your own backend authentication from the scratch.
Using OAuth¶
This implementation can be found in the official SQLAdmin side.
Permissions¶
Esmerald Admin uses the same base as SQLAdmin but adds some extra uniquenesses to it such as the pattern for the permissions.
In Esmerald, the permissions are extremely powerfull and yet simple to implement. Esmerald admin opted to follow the same pattern.
What is is_accessible
in SQLAdmin, in Esmerald admin is called has_permission
.
This way the consistency is maintained and the common systax preserved.
The ModelView
and the BaseView
classes in Esmerald Admin also implement two methods you can
override. These methods are used for the control of each Model/View in addition to the
AuthenticationBackend
.
is_visible
- Controls if the Model/View should be displayed in the menu or not.has_permission
- Controls if the Model/View should be accessed.
Like SQLAdmin, both methods implement the same signature and should return a bool
.
from esmerald import Request
from esmerald.contrib.auth.saffier.base_user import AbstractUser
from saffier import Database, Registry
from esmerald_admin import ModelView
database = Database("sqlite:///db.sqlite")
registry = Registry(database=database)
class User(AbstractUser):
"""Inherits from the user base"""
class Meta:
registry = registry
# Use the declarative from Saffier
UserDeclarative = User.declarative()
class UserAdmin(ModelView, model=UserDeclarative):
def is_visible(self, request: Request) -> bool:
# Check incoming request
# For example request.session if using AuthenticationBackend
return True
def has_permission(self, request: Request) -> bool:
# Check incoming request
# For example request.session if using AuthenticationBackend
return True
from edgy import Database, Registry
from esmerald import Request
from esmerald.contrib.auth.edgy.base_user import AbstractUser
from esmerald_admin import ModelView
database = Database("sqlite:///db.sqlite")
registry = Registry(database=database)
class User(AbstractUser):
"""Inherits from the user base"""
class Meta:
registry = registry
# Use the declarative from Saffier
UserDeclarative = User.declarative()
class UserAdmin(ModelView, model=UserDeclarative):
def is_visible(self, request: Request) -> bool:
# Check incoming request
# For example request.session if using AuthenticationBackend
return True
def has_permission(self, request: Request) -> bool:
# Check incoming request
# For example request.session if using AuthenticationBackend
return True