Class-based view mixins¶
For class-based views, three mixins live in multifactor.mixins. They sit
alongside the @multifactor_protected decorator and offer slightly different
semantics — they are not a one-to-one replacement.
The three mixins¶
Mixin |
Behaviour |
|---|---|
|
Annotates |
|
“Hard” mode. If the user is not currently MFA-authenticated, they are redirected — to |
|
“Soft” mode. If the user already has factors, they must be MFA-authenticated. If they have no factors, the view runs normally. |
Source: multifactor/mixins.py.
Choosing between decorator and mixin¶
Need |
Decorator |
Mixin |
|---|---|---|
“Require N factors” |
|
No direct equivalent — mixins do not understand factor counts. |
“Require any factor if user has factors” |
|
|
“Force users to enrol now” |
Not directly supported. |
|
|
Yes. |
No. |
Annotate |
No. |
|
Rule of thumb: prefer the decorator unless you need the enrol-forcing
behaviour of RequireMultiAuthMixin, or unless you want self.active_factors
visible from inside template/context code.
Examples¶
Read-only annotation — show different UI for MFA users¶
from django.views.generic import TemplateView
from multifactor.mixins import MultiFactorMixin
class Dashboard(MultiFactorMixin, TemplateView):
template_name = "dashboard.html"
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx["mfa_active"] = bool(self.active_factors)
ctx["mfa_enrolled"] = self.has_multifactor
return ctx
The view runs whether or not the user is MFA-authenticated; you can render a “you’re using MFA” badge in the template based on the flags.
Force enrolment for staff¶
from django.views.generic import TemplateView
from multifactor.mixins import RequireMultiAuthMixin
class AdminConsole(RequireMultiAuthMixin, TemplateView):
template_name = "admin/console.html"
A staff user hitting this view who has no factors registered is sent to the Add factor page. They are then required to enrol before they can proceed. This is opinionated and aggressive — useful for ops dashboards where you’ve decided “no MFA, no access”.
Soft prefer — never block, but challenge if enrolled¶
from django.views.generic import TemplateView
from multifactor.mixins import PreferMultiAuthMixin
class AccountSettings(PreferMultiAuthMixin, TemplateView):
template_name = "account.html"
Users with factors are challenged. Users without factors are let through.
Equivalent to @multifactor_protected(factors=0) but cleaner on CBVs.
What the mixins do not do¶
They do not check
max_age. If you need timing, use the decorator or readactive_factorsinsidedispatch()yourself.They do not support a callable factor count.
They do not integrate
user_filter— either subclass and overridedispatch, or use the decorator instead.
Combining a mixin with the decorator¶
It is legal (and occasionally useful) to use both:
from django.utils.decorators import method_decorator
@method_decorator(multifactor_protected(factors=2, max_age=300), name="dispatch")
class HighValue(PreferMultiAuthMixin, TemplateView):
template_name = "transfer.html"
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx["last_verified"] = (
self.active_factors[0][2] if self.active_factors else None
)
return ctx
The decorator enforces the factor count and age; the mixin gives the template
visibility into active_factors.
See also¶
Protecting views — the decorator equivalent.
multifactor.mixinsreference — full API.