Vue3+TypeScript+Django Rest Framework 搭建个人博客(二):用户登录功能

本文介绍了如何使用Vue3、TypeScript和Django Rest Framework搭建个人博客,重点讲解了用户登录功能的实现,包括需求分析、后端接口开发和前端页面开发。后端涉及登录、登出、修改密码接口的编写,前端涉及登录信息的保存、页面和组件的创建。整个流程详细阐述了从接口设计到前端页面展示的全过程。
摘要由CSDN通过智能技术生成

用户登录功能是一个信息系统必不可少的一部分,作为博客网站,同样需要管理员登录管理后台,游客注册后登录评论等

大家好,我是落霞孤鹜,上一篇我们已经搭建好了前后端的框架的代码,并调通了前后端接口。从这一篇开始,进入到业务功能开发进程中。

首先我们需要实现的功能是用户登录,用户登录功能虽然在系统开发中已经很成熟,但是当我们自己动手做的时候,会发现这个功能是那种典型的说起来容易,做起来复杂的功能,需要考虑和处理的点很多。

一、需求分析

1.1 完整需求

一个完整的用户登录功能,需要考虑的点如下:

  • 账号和密码的格式
  • 支持邮箱、账号、手机号码登录
  • 手机号码支持验证码登录
  • 密码错误的次数
  • 忘记密码功能
  • 注册功能
  • 新用户首次登录自动注册功能
  • 社交平台账号鉴权登录
  • 支持记住账号
  • 7天自动登录
  • 登录状态保持
  • 权限鉴定
  • 登出
  • 密码修改

在前后端分离的状态下,我们还需要考虑跨域问题

1.2 博客网站需求

考虑到我们的博客系统是个人博客,用户登录的场景主要集中在游客评论,管理员登录管理后台两个场景,所以登录功能可以适当做删减。

该博客系统的登录功能主要实现以下几个点:

  • 账号和密码的格式
  • 支持邮箱、账号
  • 忘记密码功能
  • 注册功能
  • 登录状态保持
  • 权限鉴定
  • 登出
  • 密码修改

以上功能点,满足博客网站基本需求

  • 未登录的游客只能留言,不能评论
  • 游客登录后可以评论博客
  • 游客登录后可以修改密码
  • 管理员登录后可以管理博客后台

二、后端接口开发

用户登录和鉴权实际上在 Django 里面已经有完整的功能,但是由于我们使用的是前后端分离架构,在 Django 的基础上使用了 Django Rest Framework ,因此原有的 Django 登录和鉴权接口需要做改造和调整,以适应前后端分离功能。

这里需要处理几个点:

  1. 用户登录,账号密码校验,Session保持
  2. API 鉴权,也即:接口是否是登录后才能使用,还是不登录也可以使用)
  3. 密码修改和重置

2.1 配置鉴权模式

这里采用 Django Rest Framework 提供的基于 DjangoSession 方案,如果你想采用 JWT介绍)方案,可以按照官网教程Authentication - Django REST framework进行配置。在 project/settings.py 中的 REST_FRAMWORK 配置项中修改如下:

REST_FRAMEWORK = {
   
  'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
	],
  'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
	'PAGE_SIZE': 10
}

2.2 编写登录登出接口

2.2.1 增加 UserLoginSerializer

common/serializers.py 文件中,增加代码,修改后代码如下:

from rest_framework import serializers

from common.models import User


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'avatar', 'email', 'is_active', 'created_at', 'nickname']


class UserLoginSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'password']
        extra_kwargs = {
   
            'password': {
   'write_only': True},
        }

2.2.2 增加 UserLoginViewSet

common/views.py 中增加 UserLoginViewSet 类,使用Django 自带的 authenticatelogin ,完成用户的登录,并返回用户登录信息,在这个过程中,Response 中会创建 Session,保存登录后的 user 信息,生成Cookies 一并返回。方法修改后代码如下:

from django.contrib.auth import authenticate, login
from rest_framework import viewsets, permissions
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response

from common.models import User
from common.serializers import UserSerializer, UserLoginSerializer


class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('username')
    serializer_class = UserSerializer
    permission_classes = [permissions.AllowAny]


class UserLoginViewSet(GenericAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = UserLoginSerializer
    queryset = User.objects.all()

    def post(self, request, *args, **kwargs):
        username = request.data.get('username', '')
        password = request.data.get('password', '')

        user = authenticate(username=username, password=password)
        if user is not None and user.is_active:
            login(request, user)
            serializer = UserSerializer(user)
            return Response(serializer.data, status=200)
        else:
            ret = {
   'detail': 'Username or password is wrong'}
            return Response(ret, status=403)
2.2.3 增加 UserLogoutViewSet

common/views.py 中增加 UserLogoutViewSet 类,使用Django 自带的 auth_logout ,完成用户的登出,并返回登出成功信息,这个过程中,Django 会自动清理 SessionCookies

class UserLogoutViewSet(GenericAPIView):
    permission_classes = [permissions.IsAuthenticated]
    serializer_class = UserLoginSerializer

    def get(self, request, *args, **kwargs):
        auth_logout(request)
        return Response({
   'detail': 'logout successful !'})
2.2.4 配置路由

common/urls.py 中增加 user/loginuser/logout 路由,代码如下:

from django.conf.urls import url
from django.urls import include, path
from rest_framework import routers

from common import views

router = routers.DefaultRouter()
router.register('user', views.UserViewSet)

app_name = 'common'

urlpatterns = [
    path('', include(router.urls)),
    url(r'^user/login', views.UserLoginViewSet.as_view()),
    url(r'^user/logout', views.UserLogoutViewSet.as_view()),
]

2.3 编写修改密码接口

2.3.1 增加 UserPasswordSerializer

common/serializers.py 文件中增加类 UserPasswordSerializer,主要是因为修改密码时需要提供原密码和新密码,所以单独创建一个 serializer ,代码如下:

class UserPasswordSerializer(serializers.ModelSerializer):
    new_password = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ['id', 'username', 'password', 'new_password']

    @staticmethod
    def get_new_password(obj):
        return obj.password or ''
2.3.2 增加 PasswordUpdateViewSet

密码修改的方式有两种,一种是通过修改密码功能修改,这个时候需要知道自己的原密码,然后修改成自己想要的新密码,一种是通过忘记密码功能修改,这个时候不需要知道自己的密码,但需要知道自己绑定的邮箱,新密码发送到邮箱里面。

  1. common/views.py 中增加一个方法:get_random_password,该方法用来生成一个随即的密码,支撑忘记密码功能
def get_random_password():
    import random
    import string
    return ''.join(random.sample(string.ascii_letters + string.digits + string.punctuation, 8))
  1. 安装发送邮件所需要的依赖
pip install django-smtp-ssl==1.0
  1. 同时在 requirements.txt 文件中增加依赖
django-smtp-ssl==1.0
  1. project/settings.py 中增加邮箱配置,这里的 EMAIL_HOSTEMAIL_PORT 是需要依据填写的邮箱做出调整,我这里填写的是网易的 163 邮箱
EMAIL_BACKEND = 'django_smtp_ssl.SSLEmailBackend'
MAILER_EMAIL_BACKEND = EMAIL_BACKEND
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 465
EMAIL_HOST_USER = 'zgj0607@163.com'
EMAIL_HOST_PASSWORD = 'xxxx'
EMAIL_SUBJECT_PREFIX = u'[LSS]'
EMAIL_USE_SSL = True
  1. common/views.py 中增加 PasswordUpdateViewSet,提供请求方式的接口。post 用来完成修改密码功能。
class PasswordUpdateViewSet(GenericAPIView):
    permission_classes = [permissions.IsAuthenticated]
    serializer_class = UserPasswordSerializer
    queryset = User.objects.all()

    def post(self, request, *args, **kwargs):
        user_id = request.user.id
        password = request.data.get('password', '')
        new_password = request.data.get('new_password', '')
        user = User.objects.get(id=user_id)
        if not user.check_password(password):
            ret = {
   'detail': 'old password is wrong !'}
            return Response(ret, status=403)

        user.set_password(new_password)
        user.save()
        return Response({
   
            'detail': 'password changed successful !'
        })

  1. UserLoginViewSet 中增加 put 方法,用于完成忘记密码功能,send_mail 使用的是 from django.core.mail import send_mail 语句导入。

将忘记密码的功能放在 LoginViewSet 类下的原因是登录接口和忘记密码的接口均是在不需要登录的情况下调用的接口,因此通过请求方式的不同来区分两种接口。

class UserLoginViewSet(GenericAPIView):
    permission_classes = [permissi
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值