如何在Django登录页面中添加otp身份验证

2024-09-28 19:03:56 发布

您现在位置:Python中文网/ 问答频道 /正文

首先,一旦输入并提交了电子邮件(用户名),login.html应该要求输入“Enter OTP”。如果用户存在,则使用用户表检查此用户名。如果用户存在,它应该向为此用户实例注册的移动设备发送OTP。在进入OTP时,用户应获得相应的消息以重置密码或获取主页。 我不想使用django otp应用程序。到目前为止我所做的: 在django accounts/registration/templates/login.html中

{% extends "admin/base_site.html" %}
{% load i18n static %}

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/login.css" %}">
{{ form.media }}
{% endblock %}

{% block bodyclass %}{{ block.super }} login{% endblock %}

{% block usertools %}{% endblock %}

{% block nav-global %}{% endblock %}

{% block content_title %}{% endblock %}

{% block breadcrumbs %}{% endblock %}

{% block content %}
{% if form.errors and not form.non_field_errors %}
<p class="errornote">
{% if form.errors.items|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
</p>
{% endif %}

{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<p class="errornote">
    {{ error }}
</p>
{% endfor %}
{% endif %}

<div id="content-main">

{% if user.is_authenticated %}
<p class="errornote">
{% blocktrans trimmed %}
    You are authenticated as {{ username }}, but are not authorized to
    access this page. Would you like to login to a different account?
{% endblocktrans %}
</p>
{% endif %}

<form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
  <div class="form-row">
    {{ form.username.errors }}
    {{ 'Email:' }} {{ form.username }}
  </div>
  <div class="form-row">
    {{ form.password.errors }}
    <!-- {{ form.password.label_tag }} {{ form.password }} -->
    <input type="hidden" name="next" value="{{ next }}">
  </div>
  {% url 'admin_password_reset' as password_reset_url %}
  {% if password_reset_url %}
  {% comment %}
  <div class="password-reset-link">
    <a href="{{ password_reset_url }}">{% trans 'Forgotten your password or username?' %}</a>
  </div>
  {% endcomment %}

  {% endif %}
  <div>
    {% trans 'Enter OTP' %}</a>
    <input type="integer" name="otp" value="{{ otp }}">
  </div>


  <div class="submit-row">
    <label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}">
  </div>
</form>

</div>
{% endblock %}

认证表格:

from django import forms
from django.db.models import IntegerField
from django.contrib.auth.forms import AuthenticationForm, UsernameField

class AuthenticationForm(AuthenticationForm):
    class Meta:
        model = User
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(AuthenticationForm, self).__init__(*args, **kwargs)

        for field in self.fields.values():
            field.error_messages = {'required':'{fieldname} is required'.format(
            fieldname=field.label)}
            
        username = UsernameField(
            label='Email',
            widget=forms.TextInput(attrs={'autofocus': True})
        )

        otp = IntegerField()

myauthentication后端代码:

from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.contrib.auth.models import User, Group
from myapp.models import *
from django.http import *
from datetime import datetime
from django.urls import reverse
from django.utils.translation import ugettext as _
from myapp.forms import AuthenticationForm

import pyotp
from rest_framework.response import Response
from rest_framework.views import APIView
import base64

def generateKey(phone):
    return str(phone) + str(datetime.date(datetime.now())) + "Some Random Secret Key"

class EmailBackend(ModelBackend):
    #@staticmethod
    def authenticate(self, request, username=None, password=None, **kwargs):
        mMobile = None
        user = None
        form = AuthenticationForm(request=request, data=request.GET)
        if request.GET:
            try:
                #to allow authentication through phone number or any other
                #field, modify the below statement
                user = UserModel.objects.get(
                    Q(username__iexact=username) | Q(email__iexact=username))
            except UserModel.DoesNotExist:
                print('iiii')
                UserModel().set_password(password)
            except MultipleObjectsReturned:
                print(222222)
                user = User.objects.filter(email=username).order_by('id').first()
            else:
                if user.check_password(password) and self.user_can_authenticate(
                    user):
        form = AuthenticationForm(request=request, data=request.POST)
        if form['username']:
            try:
                mMobile = Mailbox.objects.get(email=form['username'].value())
                #print(user,mMobile, 'uuu-mmmm', dir(mMobile))
            except Exception as e:
                print(e)
            #return user
        
            if mMobile:
                mMobile.counter += 1  # Update Counter At every Call
                mMobile.save()  # SamMove the data
                print(mMobile.mobile)
                keygen = generateKey(mMobile.mobile)
                # Key is generated
                key = base64.b32encode(keygen.encode())
                OTP = pyotp.HOTP(key)
                motp = (OTP.at(mMobile.counter))
                print(motp, 'oooottttpp')

                if request.POST:
                    if str(motp) == form.data['otp']:
                        print(form.data['otp'],'ddddd')
                        return user
                    else:
                        return
                return
                # Using Multi-Threading send the OTP Using Messaging
                # Services like Twilio or Fast2sms                
                #return user
            else:
                return user

    def get_user(self, user_id):
        try:
            user = UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None

        return user if self.user_can_authenticate(user) else None

问题:输入用户名并提交时,应发送otp短信。现在,它在提交表单时发送otp。如何准确地将此合并到登录表单可以重新提交2次的情况下?使用Django3.1,postgresql数据库。我需要确切的代码一些部分,比如我在这里使用的otp生成:[https://github.com/Akash16s/OTP-in-django][1]

[1]:https://github.com/Akash16s/OTP-in-django感觉被卡住了。怎么办


Tags: djangofromimportdivformreturnifusername