python - 如何在 django 登录页面中添加 otp 身份验证

标签 python django postgresql

首先,一旦输入并提交电子邮件(用户名),login.html 应要求“输入 OTP”。如果用户存在,则使用用户表检查该用户名。如果 user 存在,它应该向为此用户实例注册的移动设备发送 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 次?使用 django 3.1,postgresql 数据库。我需要确切的代码一些部分,例如我从这里使用的 otp 生成:[https://github.com/Akash16s/OTP-in-django][1]
[1]:https://github.com/Akash16s/OTP-in-django感觉卡住了。怎么去?

最佳答案

我觉得你应该看看django_otp ,如果你不想使用那个包,那么看看代码:https://github.com/django-otp/django-otp
也看看这篇博客文章,它可能有用:https://medium.com/@ksarthak4ever/django-two-factor-authentication-2ece42748610

关于python - 如何在 django 登录页面中添加 otp 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66775071/

相关文章:

Django Admin 在编辑时将 extra 设置为 0

python - OpenERP 7 自定义采购订单规则

sql - 如何查询存储在数组中的 Rails ActiveRecord 数据

sql - 如何在 PostgreSQL 中编写 upsert 触发器?

python - for 循环中的绘图和文本顺序错误

Python:删除某些字符之前的所有内容

python - 测试(unittest)变量是否是 python 中的非空字符串的正确方法?

python - 使用 Django 进行日期过滤——如何将开始和结束日期发送到我的 View ?

python - 为 parent 与 child 和 sibling 建立 M2M 关系

python - 如何在python中创建分组条形图的子图