Django拓展auth 用户 part_2

Django拓展auth 用户

完成注册登录登出注销操作

!!!拓展auth用户请务必在 python manage.py migrate 前进行!!!

  1. 新建一个project:closetUsers

  2. 修改 settings.py

    #closetUsers/settings.py
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'users',  # modify 
        'rest_framework', # modify 
        'django_filters', # modify 
    ]
    #update database config 
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'closetUser',
            'USER': 'may',
            'PASSWORD': 'may233',
            'HOST': '120.76.62.132',
            'PORT': '3306',
        }
    }
    #add auth_user_model !after! add the extended user
    AUTH_USER_MODEL = 'users.User'   #pattern: <appName>.<className>
    
    
  3. 新建一个app:users

  4. 修改 users/__init__.py

    #users/__init__.py
    import pymysql
    pymysql.install_as_MySQLdb()
    #use for django2.x version to link mysql database
    
  5. users底下添加文件 urls.py ,修改 closetUsers.urls.py

    #closetUsers/urls.py
    from django.contrib import admin
    from django.urls import path
    from django.conf.urls import include  #add this
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include('users.urls')), 
        #add this, pattern: <appName>.urls
    ]
    
  6. 修改 users.models.py, 添加拓展的用户类,继承自 AbstractUser, 注:如原来的auth.User 已有的属性不需要再添加

    #users/models.py
    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    
    # Create your models here.
    class User(AbstractUser):
        """
        save the user info
        """
        style = models.CharField(max_length=30, default='casual', null=True, blank=True)
        profile = models.URLField(default='http://120.76.62.132:8080/photos/40padded.jpg', blank=True)
        phone = models.CharField(max_length=11,  null=True, blank=True)
    
        def __str__(self):
            return self.username
    
    
  7. 建表

    xxxdeMacBook-Pro:closetUsers xxx$ python3 manage.py migrate
    xxxdeMacBook-Pro:closetUsers xxx$ python3 manage.py makemigrations users
    xxxdeMacBook-Pro:closetUsers xxx$ python3 manage.py migrate users
    
  8. 重写UserCreationForm, UserChangeForm, 在users 底下新建 form.py文件,其实我只是想要提供一个restful的API而不是建立一个网站,因而应该不需要使用到表单创建,但Django文档中说明拓展User需要重写这两个表单因此还是重写了。

    #users/forms.py
    from django.contrib.auth.forms import UserCreationForm, UserChangeForm
    from django import forms
    from .models import User
    
    
    class RegisterForm(UserCreationForm):
    
        class Meta(UserCreationForm.Meta):
            model = User
            fields = ('username', 'email', 'phone', 'style', 'profile')
    
        # check if email is valid
        def clean_email(self):
            email = self.cleaned_data['email']
            users = User.objects.filter(email=email)
            if users:
                raise forms.ValidationError("该邮箱已注册过,尝试登录?")
            return email
    
    
    class ChangeInfoForm(UserChangeForm):
    
        class Meta(UserChangeForm.Meta):
            model = User
            fields = ('username', 'email', 'phone', 'style', 'profile')
    
    
    

一、注册

法一:暴力解决

  1. 在 views.py中添加相关类或函数

    #users/views.py
    from django.shortcuts import render
    from django.http import JsonResponse, HttpResponse
    from rest_framework import status
    from .models import User
    
    
    # Create your views here.
    def sign_up(request):
        username = request.data['username']
        password = request.data['password']
        users = User.objects.filter(username=username)
        if users:
            return HttpResponse('该用户已存在', status=status.HTTP_400_BAD_REQUEST)
        user = User.objects.create_user(username=username, password=password)
        return HttpResponse('创建成功,登录?', status=status.HTTP_200_OK)
    
  2. urls.py 中添加相关路径

    #users/urls.py
    from django.urls import path
    from rest_framework.urlpatterns import format_suffix_patterns
    from users import views
    
    urlpatterns = format_suffix_patterns([
        path('users/add1/', views.sign_up),
    ])
    
  3. 使用 httpie 模拟post请求

    #pattern: http post <urlAddress> @<jsonFileAddress>
    luomeideMacBook-Pro:closetUsers luomei$ http --json post http://127.0.0.1:8000/users/add1/ @/Users/luomei/Desktop/closet/jsonTest/login.json
    HTTP/1.1 403 Forbidden
    

    Error: HTTP/1.1 403 Forbidden, CSRF verification failed. Request aborted.

    **Solve: ** 为了防止跨站伪造请求,django引入了csrf机制,引入csrf_exempt

    #users/views.py
    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def sign_up(request):
    	pass
    

    **Error: ** HTTP/1.1 500 Internal Server Error,继续看报错信息,发现进行sign_up函数解析后出现错误,发现是request以json格式发送请求时,无法以request.data['username'] 的方式获取数据

    Solve:

    #users/views.py  inside sign_up function 
    import json
    post_body = request.body 
    #django2.x use body, while django1.x use raw_post_data
    data = json.loads(post_body)
    username = data['username']
    password = data['password']
    

    再次尝试使用httpie发送请求,成功!开心!

    luomeideMacBook-Pro:closetUsers luomei$ http --json post http://127.0.0.1:8000/users/add1/ @/Users/luomei/Desktop/closet/jsonTest/login.json
    HTTP/1.1 200 OK
    Content-Length: 24
    Content-Type: text/html; charset=utf-8
    Date: Sat, 22 Dec 2018 05:17:42 GMT
    Server: WSGIServer/0.2 CPython/3.7.0
    X-Frame-Options: SAMEORIGIN
    
    创建成功,登录?
    
    luomeideMacBook-Pro:closetUsers luomei$ 
    
  4. 以上只是简单的注册,下面我们来拓展一下,加上对于信息的验证,加上了对于手机号码和邮箱的格式验证

    #users/views.py
    from django.http import JsonResponse, HttpResponse
    from rest_framework import status
    from .models import User
    from django.views.decorators.csrf import csrf_exempt
    import json
    from django.contrib.auth import login, authenticate, logout
    import re
    
    
    # Create your views here.
    @csrf_exempt
    def sign_up(request):
    
        if request.method == 'POST':
            post_body = request.body
            data = json.loads(post_body)
            if 'username' in data:
                username = data['username']
            else:
                username = 'may'
            password = data['password']
            if 'email' in data:
                email = data['email']
                # check if email is valid
                email_pat = re.compile(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$')
                if not re.match(email_pat, email):
                    return JsonResponse(data={"msg": "请输入正确的邮箱名"}, status=status.HTTP_400_BAD_REQUEST)
            else:
                email = 'error'
            if 'phone' in data:
                phone = data['phone']
                # check if phone is valid
                phone_pat = re.compile(r'^(13\d|14[5|7]|15\d|166|17[3|6|7]|18\d)\d{8}$')
                if not re.match(phone_pat, phone):
                    return JsonResponse(data={"msg": "请输入正确的手机号"}, status=status.HTTP_400_BAD_REQUEST)
            else:
                phone = 'error'
            if 'profile' in data:
                profile = data['profile']
            else:
                profile = 'http://120.76.62.132:8080/photos/default.jpg'
            if 'style' in data:
                style = data['style']
            else:
                style = 'casual'
            # users = User.objects.filter(username=username)
            email_users = User.objects.filter(email=email)
            phone_users = User.objects.filter(phone=phone)
            name_users = User.objects.filter(username=username)
            if email_users:
                return JsonResponse(data={"msg": "该邮箱已注册过"}, status=status.HTTP_400_BAD_REQUEST)
            if phone_users:
                return JsonResponse(data={"msg": "该手机号已注册过"}, status=status.HTTP_400_BAD_REQUEST)
            if name_users:
                return JsonResponse(data={"msg": "该用户已存在"}, status=status.HTTP_400_BAD_REQUEST)
            if email == 'error':
                email = ''
            if phone == 'error':
                phone = ''
            user = User.objects.create_user(username=username, password=password, email=email,
                                            phone=phone, style=style, profile=profile)
            return JsonResponse(data={"msg": "创建成功,登录?"}, status=status.HTTP_200_OK)
    

法二:django-rest-framework

尝试用django-rest-framework提供的方法实现

二、登录

法一:沿袭我们的暴力方案

2.1 使用auth模块提供的login

使用username和password登录

#users/views.py
@csrf_exempt
def sign_in(request):

    if request.method == 'POST':
        post_body = request.body
        data = json.loads(post_body)
        username = data['username']
        password = data['password']
        print(username)
        user = authenticate(username=username, password=password)
        if user:
            if user.is_active:
                login(request, user)
                print(request.user)
                return JsonResponse(data={"msg": "OK"}, status=status.HTTP_200_OK)
            else:
                return JsonResponse(data={"msg": "用户不存在"}, status=status.HTTP_400_BAD_REQUEST)
        else:
            return JsonResponse(data={"msg": "用户或密码错误"}, status=status.HTTP_400_BAD_REQUEST)

2.2 拓展,自定义后端,使用邮箱登录

参考自定义认证后台

  1. 添加 backends.py文件

    from .models import User
    
    class EmailBackend(object):
    
        def authenticate(self, request, **credentials):
            # 要注意登录表单中用户输入的用户名或者邮箱的 field 名均为 username
            email = credentials.get('email', credentials.get('username'))
            try:
                user = User.objects.get(email=email)
            except User.DoesNotExist:
                pass
            else:
                if user.check_password(credentials["password"]):
                    return user
    
        def get_user(self, user_id):
            """
            该方法是必须的
            """
            try:
                return User.objects.get(pk=user_id)
            except User.DoesNotExist:
                return None
    
    
  2. setttings.py 中加入后端文件告诉Django 你使用了自定义后端

    AUTHENTICATION_BACKENDS = (
        'django.contrib.auth.backends.ModelBackend',
        'users.backends.EmailBackend',
        'users.backends.PhoneBackend',
    )
    

2.3 同理拓展,自定义后端,使用手机登录

代码大同小异,不赘述了

三、登出

法一:继续,暴力解决一切事物

#users/views.py
@csrf_exempt
def sign_out(request):

    if request.method == 'GET':
        logout(request)
        return JsonResponse(data={"msg": "登出成功"}, status=status.HTTP_200_OK)

四、注销

法一:继续,暴力解决一切事物

#users/views.py
@csrf_exempt
def sign_off(request):

    if request.method == 'POST':
        post_body = request.body
        data = json.loads(post_body)
        username = data['username']
        password = data['password']
        user = authenticate(username=username, password=password)
        if user:
            email_pat = re.compile(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$')
            phone_pat = re.compile(r'^(13\d|14[5|7]|15\d|166|17[3|6|7]|18\d)\d{8}$')
            if re.match(email_pat, username):
                delete_result = User.objects.filter(email=username).delete()
            elif re.match(phone_pat, username):
                delete_result = User.objects.filter(phone=username).delete()
            else:
                delete_result = User.objects.filter(username=username).delete()
            if delete_result:
                return JsonResponse(data={"msg": "注销成功"}, status=status.HTTP_200_OK)
        return JsonResponse(data={"msg": "用户不存在"}, status=status.HTTP_400_BAD_REQUEST)

猜你喜欢

转载自blog.csdn.net/qq_36945033/article/details/85257649