繁体   English   中英

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

[英]how to add otp authentication in django login page

首先,输入并提交电子邮件(用户名)后,login.html 应要求“输入 OTP”。 如果用户存在,则使用用户表检查此用户名。 如果用户存在,它应该向为此用户实例注册的手机发送 OTP。 进入 OTP 后,用户应收到适当的消息以重置密码或进入主页。 我不想使用 django-otp 应用程序。 到目前为止我所做的:在 django 帐户/注册/模板/登录。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感觉卡住了。 go怎么讲?

我认为你应该看看django_otp ,如果你不想使用那个 package,那么看看代码: https://github.com/django-otp/django-otp

另请查看此博客文章,它可能有用: https://medium.com/@ksarthak4ever/django-two-factor-authentication-2ece42748610

这就是我使用 models.py 的方式

下面是 model.py

class Customer(models.Model):
    user = models.OneToOneField(User, null=True, blank =True, on_delete=models.CASCADE)
    date_created = models.DateTimeField(auto_now_add=True, null=True)
    name = models.CharField(max_length=200, null=True)
    first_name = models.CharField(max_length=200, null=True)
    last_name = models.CharField(max_length=200, null=True)
    email = models.CharField(max_length=200, unique=True)
    phone = models.CharField(max_length=200, null=True)
    platformLogo= models.ImageField(upload_to=upload_path, default='logo.png', null=True, blank=False)

这是我的 forms.py

from django.forms import ModelForm
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import Customer
from django import forms


class CustomerForm(ModelForm):
    class Meta:
        model = Customer
        fields  = '__all__'
        exclude = ['user', 'email','name','otp_code']


class CreateUserForm(UserCreationForm):
    class Meta:
        model = User
        fields  = ['username','first_name','last_name', 'email', 'password1', 'password2']

这是我的意见.py

def loginUser(request): 
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        try:
            user = authenticate(username=username, password=password)
            if user is not None:
                user = User.objects.get(username=username)
                otp= random.randrange(100000,999999)
                user.customer.otp_code = otp
                user.customer.save()
                request.session['username'] = username
                body = f"Dear {username}, your OTP for login is {otp}. Use this OTP to validate your login."
                send_mail('OTP request',body,'email@gmail.com',[username], fail_silently=False)
                messages.success(request, "Your OTP has been send to your email.")
                return redirect("/otp_verification")
            else:
                messages.error(request, "Wrong Credentials!!")
                return render(request,'login.html')
        except:
            messages.error(request, "Please enter email and password for login!")
            return render(request,'login.html')
    context={}    
    return render(request, "login.html", context)



def otp_verification(request):
    username = request.session['username']
    if request.method == "POST":
        otp = request.POST.get('username')
        user = User.objects.filter(username = username).first()
        if otp == user.customer.otp_code:
            messages.success(request, "OTP Success. Please login with your credentials!")
            login(request, user)
            messages.success(request, f' Wecome {username}')
            return redirect("/")
        else:
            messages.error(request, "Wrong OTP!!")
    return render(request, "otpVerification.html")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM