django_pycharm社区版4_google_auth2

django_pycharm社区版开发记录4

  • 前期准备
    • 导入包
    • 复制文件到项目app目录下
  • 修改代码
    • settings.py文件
    • models.py文件
    • gauth.py文件
    • urls.py路由文件
  • 测试
    • 调用新建用户方法
    • 绑定用户账号到google auth中
    • 登陆测试

验证django_google_auth用户认证。Google Authenticator是个开源项目,谷歌身份验证器实现原理类似于 QQ 令牌,不依赖于网络,30秒更新一次。

前期准备

导入包

pip install django-google-auth2

复制文件到项目app目录下

这3个文件复制到当前appa目录下,我们的业务方法会用到它里面的逻辑。
django_pycharm社区版4_google_auth2_第1张图片

修改代码

settings.py文件

注入django-google-auth2包到项目

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp1',
    'rest_framework',
    'rest_framework.authtoken',
    'rest_framework_jwt',
    'django_google_auth2',
]

models.py文件

google动态认证用要数据库,所以要在models.py作一些处理,它用到两个类:

from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.


class UserProfile(AbstractUser):
    #用户信息表,直接继承AbstractUser,根据需要自己修改;
    pass


用于存储秘钥的表,根用户表通过id关联
class Google2Auth(models.Model):
    """GoogleAuth"""
    user = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
    key = models.CharField(verbose_name="Google秘钥", max_length=128)

gauth.py文件

这里包括新建用户,绑定用户和认证用户三个类,实现我们的业务逻辑功能。

from drf_dynamic_fields import DynamicFieldsMixin
from rest_framework.views import APIView
from . import models
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
import base64
import codecs
import random
import re
import pyotp
from . import googletotp
from django.shortcuts import Http404
from django.db.models import Q
from rest_framework import status
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins
from django.contrib.auth import authenticate, login


class UserSerializer(DynamicFieldsMixin, serializers.ModelSerializer):
    class Meta:
        model = models.UserProfile
        fields = ["username", "password", "email", ]

    def create(self, validated_data):
        user = models.UserProfile.objects.create_user(**validated_data)  # 新增用户必须用create_user,否则密码不是秘文
        return user


# 新建用户
class createUser(mixins.CreateModelMixin, GenericViewSet):
    queryset = models.UserProfile.objects.all()
    serializer_class = UserSerializer


class googleSerializer(DynamicFieldsMixin, serializers.ModelSerializer):
    username = serializers.CharField()
    password = serializers.CharField()

    class Meta:
        model = models.UserProfile
        fields = ["username", "password", ]

    def validate_username(self, username):
        user = authenticate(username=username, password=self.initial_data["password"])
        if not user:
            raise Http404("账号密码不匹配")
        return username


# 绑定Google令牌
class googleBindAPI(APIView):
    def post(self, request):
        queryset = models.Google2Auth.objects.filter(
            Q(user__username=request.data["username"]) | Q(user__email=request.data["username"]))
        if queryset.exists():
            raise Http404("已经绑定令牌,绑定失败")
        serializer = googleSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = models.UserProfile.objects.get(Q(email=request.data["username"]) | Q(username=request.data["username"]))
        login(request, user)
        base_32_secret = base64.b32encode(
            codecs.decode(codecs.encode('{0:020x}'.format(random.getrandbits(80))), 'hex_codec'))
        totp_obj = googletotp.TOTP(base_32_secret.decode("utf-8"))  # 实例化类
        qr_code = re.sub(r'=+$', '', totp_obj.provisioning_uri(request.user.email))
        models.Google2Auth.objects.create(user=user)
        key = str(base_32_secret, encoding="utf-8")
        queryset.update(key=key)
        return Response({"success": True, "msg": "绑定成功", "results": {"qr_code": qr_code}},
                        status=status.HTTP_201_CREATED)


def Google_Verify_Result(secret_key, verifycode):
    t = pyotp.TOTP(secret_key)
    result = t.verify(verifycode)  # 对输入验证码进行校验,正确返回True
    res = result if result is True else False
    print("ret:", res)
    return res

# 用户认证
class loginView(APIView):
    def post(self, request):
        user = authenticate(username=request.data["username"], password=request.data["password"])
        if not user:
            raise Http404("账号密码不匹配")
        try:
            # 判断用户是否已经绑定Google令牌
            key = models.Google2Auth.objects.get(
                Q(user__username=request.data["username"]) | Q(user__email=request.data["username"])).key
        except:
            raise Http404("未绑定令牌")

        if not Google_Verify_Result(key, request.data["code"]):
            # 验证令牌
            return Response({"success": True, "msg": "验证码失效", "results": None}, status=status.HTTP_400_BAD_REQUEST)
        login(request, user)
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return Response({"success": True, "msg": "登录成功", "results": token}, status=status.HTTP_200_OK)

urls.py路由文件

修改urls.py把url和我们的方法联系起来

app_name = 'myapp1'
from django.conf.urls import include
from django.urls import path
from django_google_auth2.google.bindgoogleauth.bindgoogleauthapi import bind_google_auth_api
from rest_framework import routers
from . import views, gauth

createUserViewRouter = routers.DefaultRouter()                  # 新增用户
createUserViewRouter.register('', gauth.createUser,)

urlpatterns = [
    path('createuser/', include(createUserViewRouter.urls)),    # 新增用户
    path('binggoogleauth/', gauth.googleBindAPI.as_view()),     # 绑定令牌
    path('loginx/', gauth.loginView.as_view()),  #
    path('bing-google-auth-api/', bind_google_auth_api),
    path('testapi/', views.testapi),                            # 测试基础API
    path('testlogin/', views.testlogin.as_view()),              # 测试带参数的api

]

测试

调用新建用户方法

django_pycharm社区版4_google_auth2_第2张图片
建立用户返回成功。

绑定用户账号到google auth中

参数为刚刚新建的帐号和密码:
django_pycharm社区版4_google_auth2_第3张图片
返回结果:
django_pycharm社区版4_google_auth2_第4张图片
绑定成功。

  • 得到一段在google验证APP中识别的代码:
 {
    "success": true,
    "msg": "绑定成功",
    "results": {
        "qr_code": "otpauth://totp/[email protected]?secret=VRDIV5XHMVVU637N"
    }
}

把这段代码生成二维码或者手动输入到google验证APP中去,就可以实时生成动态密码了:
django_pycharm社区版4_google_auth2_第5张图片

登陆测试

在浏览器输入:http://127.0.0.1:8000/myapp1/loginx/参数为:帐号、密码和动态密码
django_pycharm社区版4_google_auth2_第6张图片
结果返回登陆成功,同时返回最新有效的token。
django_pycharm社区版4_google_auth2_第7张图片
失败返回出错信息
django_pycharm社区版4_google_auth2_第8张图片

你可能感兴趣的:(Django,Python)