· 5 years ago · May 27, 2020, 10:36 AM
1requirements/base.txt
2============================
3# OPT
4# ------------------------------------------------------------------------------
5django-otp==0.9.0 # https://github.com/django-otp/django-otp
6
7
8otp_admin.py
9===========================
10from django.conf import settings
11from django.contrib.auth.admin import GroupAdmin
12from django.contrib.auth.models import Group
13from django.contrib.sites.admin import SiteAdmin
14from django.contrib.sites.models import Site
15from django_otp.admin import OTPAdminSite
16from django_otp.plugins.otp_static.admin import StaticDeviceAdmin
17from django_otp.plugins.otp_static.models import StaticDevice
18from django_otp.plugins.otp_totp.admin import TOTPDeviceAdmin
19from django_otp.plugins.otp_totp.models import TOTPDevice
20
21if settings.DEBUG:
22 from django.contrib.admin.sites import AdminSite
23 otp_admin = AdminSite()
24else:
25 class OTPAdmin(OTPAdminSite):
26 login_template = 'admin/login.html'
27
28 def has_permission(self, request):
29 """
30 In addition to the default requirements, this only allows access to
31 users who have been verified by a registered OTP device and this device is not an email.
32 """
33 return super(OTPAdmin, self).has_permission(request) and not hasattr(request.user.otp_device, 'email')
34
35 otp_admin = OTPAdmin(name='OTP Admin')
36
37otp_admin.register(TOTPDevice, TOTPDeviceAdmin)
38otp_admin.register(StaticDevice, StaticDeviceAdmin)
39
40otp_admin.register(Group, GroupAdmin)
41otp_admin.register(Site, SiteAdmin)
42
43
44templates/admin/login.html
45==========================
46
47{% extends "admin/login.html" %}
48{% load i18n static %}
49
50{% block content %}
51 <style>
52 .login .form-row #id_otp_token {
53 clear: both;
54 padding: 8px;
55 width: 100%;
56 -webkit-box-sizing: border-box;
57 -moz-box-sizing: border-box;
58 box-sizing: border-box;
59 }
60 </style>
61 {% if form.errors and not form.non_field_errors %}
62 <p class="errornote">
63 {% if form.errors.items|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
64 </p>
65 {% endif %}
66
67{% if form.non_field_errors %}
68 {% for error in form.non_field_errors %}
69 <p class="errornote">
70 {{ error }}
71 </p>
72 {% endfor %}
73{% endif %}
74
75<div id="content-main">
76
77 {% if user.is_authenticated %}
78 <p class="errornote">
79 {% blocktrans trimmed %}
80 You are authenticated as {{ username }}, but are not authorized to
81 access this page. Would you like to login to a different account?
82 {% endblocktrans %}
83 </p>
84 {% endif %}
85
86 <form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
87 <div class="form-row">
88 {{ form.username.errors }}
89 {{ form.username.label_tag }} {{ form.username }}
90 </div>
91 <div class="form-row">
92 {{ form.password.errors }}
93 {{ form.password.label_tag }} {{ form.password }}
94 <input type="hidden" name="next" value="{{ next }}">
95 </div>
96 <div class="form-row">
97 {{ form.otp_token.errors }}
98 {{ form.otp_token.label_tag }} {{ form.otp_token }}
99 </div>
100 {% url 'admin_password_reset' as password_reset_url %}
101 {% if password_reset_url %}
102 <div class="password-reset-link">
103 <a href="{{ password_reset_url }}">{% trans 'Forgotten your password or username?' %}</a>
104 </div>
105 {% endif %}
106 <div class="submit-row">
107 <label> </label><input type="submit" value="{% trans 'Log in' %}">
108 </div>
109 </form>
110
111</div>
112{% endblock %}
113
114
115base/urls.py
116===============================
117if not settings.DISABLE_ADMIN_PANEL:
118 from marketplace.tools.otp_admin import otp_admin
119 urlpatterns += [path(settings.ADMIN_URL, otp_admin.urls)]
120
121settings/base.py
122==============================
123DISABLE_ADMIN_PANEL = env.bool('DISABLE_ADMIN_PANEL', False)
124SECRET_KEY = "same as in the platform"
125
126INSTALLED_APPS = [
127 "django.contrib.sites",
128 'django_otp',
129 'django_otp.plugins.otp_totp',
130 'django_otp.plugins.otp_hotp',
131 'django_otp.plugins.otp_static',
132]
133
134MIDDLEWARE = [
135 "django_otp.middleware.OTPMiddleware",
136]
137
138AUTHENTICATION_BACKENDS = [
139 "marketplace.users.backends.UsernameEmailBackend",
140]
141AUTH_USER_MODEL = "users.User"
142
143
144users/backends.py
145=======================================
146from django.contrib.auth import get_user_model # gets the user_model django default or your own custom
147from django.contrib.auth.backends import ModelBackend
148from django.db.models import Q
149
150UserModel = get_user_model()
151
152
153# Class to permit the athentication using email or username
154class UsernameEmailBackend(ModelBackend): # requires to define two functions authenticate and get_user
155 def authenticate(self, request, username=None, password=None, **kwargs):
156 user = UserModel.objects.filter(
157 Q(username=username) |
158 Q(email__iexact=username)
159 ).distinct()
160
161 if user.exists():
162 ''' get the user object from the underlying query set,
163 there will only be one object since username and email
164 should be unique fields in your models.'''
165 user_obj = user.first()
166 if user_obj.check_password(password) and self.user_can_authenticate(user):
167 return user_obj
168 return None
169 else:
170 return None
171
172 def get_user(self, user_id):
173 try:
174 user = UserModel._default_manager.get(pk=user_id)
175 except UserModel.DoesNotExist:
176 return None
177 return user if self.user_can_authenticate(user) else None
178
179
180in every admin.py
181==============================
182from .otp_admin import otp_admin
183
184@admin.register(Invoice, site=otp_admin)