Django拓展auth 用户
完成注册登录登出注销操作
!!!拓展auth用户请务必在 python manage.py migrate
前进行!!!
-
新建一个project:
closetUsers
-
修改
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>
-
新建一个app:
users
-
修改
users/__init__.py
#users/__init__.py import pymysql pymysql.install_as_MySQLdb() #use for django2.x version to link mysql database
-
在
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 ]
-
修改
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
-
建表
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
-
重写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')
一、注册
法一:暴力解决
-
在 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)
-
在 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), ])
-
使用 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$
-
以上只是简单的注册,下面我们来拓展一下,加上对于信息的验证,加上了对于手机号码和邮箱的格式验证
#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 拓展,自定义后端,使用邮箱登录
-
添加 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
-
在 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)