10 登录注册之多方式登录


10 登录注册之多方式登录

一、后端

1、插件

>: pip install djangorestframework-jwt

2、多方式登录第一种方式

2.1、user/urls.py
from rest_framework.routers import SimpleRouter
from . import views
router = SimpleRouter()
router.register('', views.LoginViewSet, 'login')

urlpatterns = [

]
urlpatterns += router.urls
2.2、dev.py
import datetime
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
}
2.3、views.py
from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from . import serializers, models
from luffyapi.utils.response import APIResponse
from rest_framework.decorators import action


class LoginViewSet(ViewSet):
    # 局部禁用认证、权限组件
    authentication_classes = ()
    permission_classes = ()

    @action(methods=['POST'], detail=False)
    def login(self, request, *args, **kwargs):
        serializer = serializers.LoginSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            token = serializer.context.get('token')

            # 原来要一个个拿信息
            # username = serializer.context.get('username')
            # icon = serializer.context.get('icon')

            # 拿到登录用户,直接走序列化过程,将要返回给前台的数据直接序列化好给前台
            user = serializer.context.get('user')
            result = serializers.LoginSerializer(user, context={'request': request}).data
            result['token'] = token  # id,username,icon,token
            return APIResponse(result=result)
        return APIResponse(1, serializer.errors)
2.4、serializers.py
from rest_framework import serializers
from rest_framework import exceptions
from django.conf import settings
from . import models

class LoginSerializer(serializers.ModelSerializer):
    # 覆盖,避免login校验username有数据库唯一字段约束的限制
    username = serializers.CharField()

    class Meta:
        model = models.User
        # username、password可以通过局部钩子指定详细的校验规则
        fields = ('id', 'username', 'password', 'icon')
        extra_kwargs = {
            'id': {
                'read_only': True,
            },
            'icon': {
                'read_only': True,
            },
            'password': {
                'write_only': True,
            }
        }

    def validate(self, attrs):
        # 多方式得到user
        user = self._get_user(attrs)
        # user签发token
        token = self._get_token(user)
        # token用context属性携带给视图类
        self.context['token'] = token

        ''' 自己将user的信息逐个处理,传给视图
        # 前台可能不仅仅只需要登录成功的token,可能还需要用户名、用户头像等
        self.context['username'] = user.username

        # 通过请求头格式化icon
        request = self.context['request']
        icon = 'http://%s%s%s' % (request.META['HTTP_HOST'], settings.MEDIA_URL, user.icon)
        self.context['icon'] = icon
        '''
        # 将登录用户对象直接传给视图
        self.context['user'] = user

        return attrs

    def _get_user(self, attrs):
        import re
        username = attrs.get('username')
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = models.User.objects.filter(mobile=username).first()
        else:
            user = models.User.objects.filter(username=username).first()
        if not user:
            raise exceptions.ValidationError({'username': 'username error'})

        password = attrs.get('password')
        if not user.check_password(password):
            raise exceptions.ValidationError({'password': 'password error'})

        return user

    def _get_token(self, user):
        from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
        payload = jwt_payload_handler(user)  # 通过user对象获得payload
        token = jwt_encode_handler(payload)  # 通过payload对象获得token
        return token

3、多方式登录第二种方式

3.1、user/urls.py
from django.urls import path
from . import views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('', views.UserView, 'user')
router.register('', views.LoginView, 'login')

urlpatterns = [

]

urlpatterns += router.urls
3.2、user/views.py
# 多方式登录接口
class LoginView(GenericViewSet):
    serializer_class = LoginSerializer

    @action(methods=['POST'], detail=False)
    def mul_login(self, request, *args, **kwargs):
        try:
            # 校验规则和签发token都写到序列化类中
            ser = self.get_serializer(data=request.data, context={'request': request})
            # context是视图类和序列化类中的桥梁,可以通过context互相传值,因为序列化类用到request,所以传值
            ser.is_valid(raise_exception=True)
            token = ser.context.get('token')
            username = ser.context.get('username')
            icon = ser.context.get('icon')
        except Exception as e:
            raise APIException(str(e))
        return APIResponse(token=token, username=username, icon=icon)
3.3、user/serializers.py
from rest_framework import serializers
from .models import User
import re
from rest_framework.exceptions import ValidationError


class LoginSerializer(serializers.ModelSerializer):
    # 因为username自己会有唯一键,所以要重写username字段
    username = serializers.CharField()

    class Meta:
        model = User
        fields = ['id', 'username', 'password', 'icon']
        extra_kwargs = {
            'id': {'read_only': True},
            'username': {'read_only': True},
            'password': {'write_only': True},
            'icon': {'read_only': True}
        }

    def validate(self, attrs):
        # 1.获取登录用户和密码
        user = self._get_user(attrs)
        # 2.签发token
        token = self._get_token(user)
        # 3.把token放入当前对象给视图类用
        self.context['token'] = token
        self.context['username'] = user.username
        # 这个地址是服务端地址,服务端地址从request对象中可以取出request.META['HTTP_HOST']
        request = self.context.get('request')
        self.context['icon'] = 'http://%s/media/'%request.META['HTTP_HOST']+str(user.icon)
        return attrs

    def _get_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = User.objects.filter(telephone=username).first()
        elif re.match(r'^.+@.+$', username):
            user = User.objects.filter(email=username).first()
        else:
            user = User.objects.filter(username=username).first()

        if user and user.check_password(password):  # 使用check_password检验加密秘密
            return user
        else:
            raise ValidationError('用户名或密码错误')

    def _get_token(self, user):
        from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
        payload = jwt_payload_handler(user)  # 通过user对象获得payload
        token = jwt_encode_handler(payload)  # 通过payload对象获得token
        return token

二、前端

安装:前端项目目录下的终端
cnpm install vue-cookies
配置:main.js
import cookies from 'vue-cookies'
Vue.prototype.$cookies = cookies;

1、Login.vue






2、Header.vue






3、Register.vue