Django实现注册登录 --- 传统HTTP Basic认证+Session会话

采用Django实现的注册登录功能

项目地址:https://github.com/ylpxzx/Login_DjangoAuth

主要实现内容

在这里插入图片描述

效果演示

未登录情况下,无法访问需要登录认证的页面

点击右上角的“气泡”按钮,未登录情况下,自动跳转到登录页面

在这里插入图片描述
自动跳转到登录页
在这里插入图片描述

注册演示

在这里插入图片描述
填写正确邮箱号后,邮箱将接受到激活信息,点击激活信息,即可登录

登录成功演示

在这里插入图片描述
点击右上角气泡按钮,跳转到气泡页
在这里插入图片描述

项目实现

安装所需库

pip install pillow
pip install django-simple-captcha
pip install django-simpleui
pip install six

项目目录结构

项目名为loginproject,应用名为login
在这里插入图片描述

定义模型

  • login/models.py
from django.db import models

# Create your models here.
class User(models.Model):
    gender=(
        ('male','男'),
        ('female','女'),
    )

    name=models.CharField(max_length=128,unique=True)
    password=models.CharField(max_length=256)
    email=models.EmailField(unique=True)
    sex=models.CharField(max_length=32,choices=gender,default="男")
    c_time=models.DateTimeField(auto_now_add=True)
    #新增了has_confirmed字段,这是个布尔值,默认为False,也就是未进行邮件注册;
    has_confirmed = models.BooleanField(default=False)
    def __str__(self):
        return self.name

    class Meta:
        ordering=["-c_time"]
        verbose_name="用户"
        verbose_name_plural="用户"


class ConfirmString(models.Model):
    '''
    ConfirmString模型保存了用户和注册码之间的关系,一对一的形式;
    '''
    #code字段是哈希后的注册码;
    code = models.CharField(max_length=256)
    user = models.OneToOneField('User', on_delete=models.CASCADE, )
    c_time = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.user.name + ":   " + self.code

    class Meta:
        ordering = ["-c_time"]
        verbose_name = "确认码"
        verbose_name_plural = "确认码"

配置settings.py文件

配置INSTALLED_APPS
INSTALLED_APPS = [
    'login',  # 应用名
    'simpleui',  # 后台美化
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'captcha',  # 图形验证码
]
配置静态文件static路径
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static","static"),
]
配置模板文件路径
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'static','templates')], # 添加模板文件路径
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
            'builtins':['django.templatetags.static'], # 添加该行,不用在静态模板中,手动添加{% load static %}
        },
    },
]
配置邮箱SMTP设置

可自行百度如何开启163邮箱的POP3/SMTP服务

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = '填入自己的163邮箱'
EMAIL_HOST_PASSWORD = '开启163邮箱POP3/SMTP服务后的授权密码'

# 注册有效期天数
CONFIRM_DAYS = 7

注册模型字段到后台admin

  • login/admin.py
from django.contrib import admin
from .models import *
# Register your models here.


class UserAdmin(admin.ModelAdmin):
    list_display = ('name','sex','email','password','c_time')
    list_filter = ['sex','name','c_time']
    search_fields = ['sex','name','c_time']

class ConfirmAdmin(admin.ModelAdmin):
    list_display = ('code','user','c_time')
admin.site.register(User,UserAdmin)
admin.site.register(ConfirmString,ConfirmAdmin)

配置form表单

在应用下创建forms.py文件

  • login/forms.py
from django import forms
from captcha.fields import CaptchaField


class UserForm(forms.Form):
    username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'}))
    password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    captcha = CaptchaField(label='验证码')


class RegisterForm(forms.Form):
    gender = (
        ('male', "男"),
        ('female', "女"),
    )
    username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'}))
    password1 = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    password2 = forms.CharField(label="确认密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    email = forms.EmailField(label="邮箱地址", widget=forms.EmailInput(attrs={'class': 'form-control'}))
    sex = forms.ChoiceField(label='性别', choices=gender)
    captcha = CaptchaField(label='验证码')

数据库迁移

python manage.py makemigrations
python manage.py migrate

配置路由

设计应用路由

在应用下创建urls.py文件

  • login/urls.py
from django.conf.urls import url
from .views import *
# CBV模式
urlpatterns = [
    url(r'^index/', IndexView.as_view(),name='index'),
    url(r'^login/', LoginView.as_view(),name='login'),
    url(r'^register/', RegisterView.as_view(),name='register'),
    url(r'^logout/', LogoutView.as_view(),name='logout'),
    url(r'^confirm/$', UserConfirmView.as_view(),name='confirm'),
    url(r'^content/',  ContentView.as_view(),name='content'),
]
配置根路由

与项目名同名的目录下的urls.py文件

  • loginproject/urls.py
from django.conf.urls import url
from django.conf.urls import include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'',include('login.urls')), # 配置app,login的url
    url(r'^captcha', include('captcha.urls')),  # 配置图形验证码路由
]

视图代码

  • login/views.py
import hashlib
import datetime
from django.shortcuts import render
from django.shortcuts import redirect
from . import models
from django import forms
from login import forms
from django.conf import settings
from django.views.generic import View
from functools import wraps
from django.utils.decorators import method_decorator
from django.core.mail import EmailMultiAlternatives
# Create your views here.


def hash_code(s, salt='mysite'):  # 加盐
	# 加密
    h = hashlib.sha256()
    s += salt
    h.update(s.encode())  # update方法只接收bytes类型
    return h.hexdigest()

def make_confirm_string(user):
	# 激活确定
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    code = hash_code(user.name, now)
    models.ConfirmString.objects.create(code=code, user=user,)
    return code


def send_email(email, code):
	# 邮箱发送
    subject = '来自Mr Wolf的注册确认邮件'
    text_content = '''感谢注册Mr Wolf,专注于Django实战的博客分享!\
                    如果你看到这条消息,说明你的邮箱服务器不提供HTML链接功能,请联系管理员!'''

    html_content = '''
                    <p>感谢注册<a href="http://{}/confirm/?code={}" target=blank>Mr Wolf系统</a>,\
                    专注于Django实战的博客分享!</p>
                    <p>请点击站点链接完成注册确认!</p>
                    <p>此链接有效期为{}天!</p>
                    '''.format('127.0.0.1:8000', code, settings.CONFIRM_DAYS)

    msg = EmailMultiAlternatives(subject, text_content, settings.EMAIL_HOST_USER, [email])
    msg.attach_alternative(html_content, "text/html")
    msg.send()

# session认证装饰器
def login_check(func):
    @wraps(func)
    def wrapper(request):
        if not request.session.get('is_login', None):
            return redirect("/login/")
        else:
            return func(request)
    return wrapper


# CBV模式

class IndexView(View):
    '''
    首页
    '''
    def get(self,request):
        return render(request, 'login/index.html')


class RegisterView(View):
    '''
    注册
    '''
    def get(self,request):
        register_form = forms.RegisterForm(request.POST)
        return render(request, 'login/register.html', {'message': '','register_form':register_form})

    def post(self,request):
        register_form = forms.RegisterForm(request.POST)
        if register_form.is_valid():  # 获取数据
            username = request.POST.get('username','')
            password1 = request.POST.get('password1','')
            password2 = request.POST.get('password2','')
            email = request.POST.get('email','')
            sex = request.POST.get('sex','')
            if password1 != password2:  # 判断两次密码是否相同
                message = "两次输入的密码不同!"
                return render(request, 'login/register.html', {'message': message, 'register_form': register_form})
            else:
                same_name_user = models.User.objects.filter(name=username)
                same_email_user = models.User.objects.filter(email=email)
                if same_name_user:  # 用户名唯一
                    message = '用户已经存在,请重新选择用户名!'
                    return render(request, 'login/register.html', {'message': message, 'register_form': register_form})
                elif same_email_user:  # 邮箱地址唯一
                    message = '该邮箱地址已被注册,请使用别的邮箱!'
                    return render(request, 'login/register.html', {'message': message, 'register_form': register_form})

                else:
                    # 当一切都OK的情况下,创建新用户

                    new_user = models.User()
                    new_user.name = username
                    new_user.password = hash_code(password1)  # 使用哈希加密密码
                    new_user.email = email
                    new_user.sex = sex
                    new_user.save()

                    code = make_confirm_string(new_user)
                    send_email(email, code)
                    message = '请前往注册邮箱,进行邮件确认!'
                    return render(request, 'login/confirm.html', {'message': message})  # 跳转到等待邮件确认页面。


class LoginView(View):
    '''
    登录
    '''
    def get(self,request):
        login_form = forms.UserForm(request.POST)
        return render(request,'login/login.html',{'login_form':login_form})


    def post(self,request):
        login_form = forms.UserForm(request.POST)
        message = "请检查填写的内容!"
        if login_form.is_valid():
            username = request.POST.get('username','')
            password = request.POST.get('password','')
            try:
                user = models.User.objects.get(name=username)
                if not user.has_confirmed:
                    message = "该用户还未通过邮件确认!"
                    return render(request, 'login/login.html', {'message': message,'login_form':login_form})
                if user.password == hash_code(password):  # 哈希值和数据库内的值进行比对
                    # 记录会话状态
                    request.session['is_login'] = True
                    request.session['user_id'] = user.id
                    request.session['user_name'] = user.name
                    return redirect('/index/')
                else:
                    message = "密码不正确!"
            except:
                message = "用户不存在!"
        return render(request, 'login/login.html', {'message': message,'login_form':login_form})


class LogoutView(View):
    '''
    退出
    '''
    def get(self,request):
        if not request.session.get('is_login', None):
            return redirect("/index/")
        request.session.flush()
        # 或者使用下面的方法
        # del request.session['is_login']
        # del request.session['user_id']
        # del request.session['user_name']
        return redirect("/index/")


class UserConfirmView(View):
    '''
    邮箱激活认证
    '''
    def get(self,request):
        code = request.GET.get('code', None)

        try:
            confirm = models.ConfirmString.objects.get(code=code)
        except:
            message = '无效的确认请求!'
            return render(request, 'login/confirm.html', {'message': message})

        c_time = confirm.c_time
        now = datetime.datetime.now()
        if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
            confirm.user.delete()
            message = '您的邮件已经过期!请重新注册!'
            return render(request, 'login/confirm.html', {'message': message})
        else:
            confirm.user.has_confirmed = True
            confirm.user.save()
            confirm.delete()
            message = '感谢确认,请使用账户登录!'
            login_form = forms.UserForm(request.POST)
            return render(request, 'login/login.html', {'message': message, 'login_form': login_form})


class ContentView(View):
	# 气泡页面视图,登录后才允许访问
    @method_decorator(login_check)
    def get(self,request):
        message = '验证气泡显示'
        return render(request, 'content.html', {'message': message})

前端实现

GitHub上下载参考

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狼性书生

谢谢鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值