用户登录认证
问题1:有些 API
需要用户登录成功之后才能访问,有些无需登录就能访问
models.py
from django.db import models
class UerInfo(models.Model):
user_type_choices = (
(1, '普通用户'),
(2, 'VIP'),
(3, 'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=64)
class UserToken(models.Model):
user = models.OneToOneField(to='UerInfo')
token = models.CharField(max_length=64)
登录
urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/v1/auth/$', views.AuthView.as_view()),
]
views.py
from django.http import JsonResponse
from rest_framework.views import APIView
from api import models
def md5(user):
import hashlib
import time
ctime = str(time.time())
m = hashlib.md5(bytes(user, encoding='utf-8'))
m.update(bytes(ctime, encoding='utf-8'))
return m.hexdigest()
class AuthView(APIView):
def post(self, request, *args, **kwargs):
ret = {'code': 1000, 'msg': None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UerInfo.objects.filter(username=user, password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = '用户名或密码错误'
# 为登录用户创建token
token = md5(user)
# 存在就更新, 不存在就创建
models.UserToken.objects.update_or_create(user=obj, defaults={'token': token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
解决:(认证组件的基本使用)
- 创建两张表
- 用户登录(返回 token 并保存到数据库)
认证
urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/v1/auth/$', views.AuthView.as_view()),
url(r'^api/v1/order/$', views.OrderView.as_view()),
]
views.py
class Authentication(object):
def authenticate(self, request):
token = request._request.GET.get('token')
token_obj = models.UserToken.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed('用户认证失败')
# 在rest framework内部会将这两个字段赋值给request, 以供后续操作使用
return (token_obj.user, token_obj)
def authenticate_header(self, request):
pass
class OrderView(APIView):
'''
订单相关业务
'''
authentication_classes = [Authentication, ]
def get(self, request, *args, **kwargs):
token = request._request.GET.get('token')
if not token:
return HttpResponse('用户未登录')
ret = {'code': 1000, 'msg': None, 'data': None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
这样写有一个不好之处,在每一个业务中,都需要添加 authentication_classes = [Authentication, ]
做相关认证,因此可以把它设置为全局
需要在 settings.py 中添加
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.FirstAuthentication', 'api.utils.auth.Authentication']
}
在 api 下新建 utlis,utils中新建 auth.py
# -*- coding: utf-8 -*-
from rest_framework import exceptions
from api import models
from rest_framework.authentication import BaseAuthentication
class FirstAuthentication(BaseAuthentication):
def authenticate(self, request):
pass
def authenticate_header(self, request):
pass
class Authentication(BaseAuthentication):
def authenticate(self, request):
token = request._request.GET.get('token')
token_obj = models.UserToken.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed('用户认证失败')
# 在rest framework内部会将这两个字段赋值给request, 以供后续操作使用
return (token_obj.user, token_obj)
def authenticate_header(self, request):
pass
views.py
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from api import models
ORDER_DICT = {
1: {
'name': 'qiu',
'age': 18,
'gender': '男',
'content': '...'
},
2: {
'name': 'xi',
'age': 19,
'gender': '男',
'content': '.....'
}
}
def md5(user):
import hashlib
import time
ctime = str(time.time())
m = hashlib.md5(bytes(user, encoding='utf-8'))
m.update(bytes(ctime, encoding='utf-8'))
return m.hexdigest()
class AuthView(APIView):
authentication_classes = []
def post(self, request, *args, **kwargs):
ret = {'code': 1000, 'msg': None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UerInfo.objects.filter(username=user, password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = '用户名或密码错误'
# 为登录用户创建token
token = md5(user)
# 存在就更新, 不存在就创建
models.UserToken.objects.update_or_create(user=obj, defaults={'token': token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
class OrderView(APIView):
'''
订单相关业务
'''
# authentication_classes = [FirstAuthentication, Authentication, ]
def get(self, request, *args, **kwargs):
token = request._request.GET.get('token')
if not token:
return HttpResponse('用户未登录')
ret = {'code': 1000, 'msg': None, 'data': None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
class UserInfoView(APIView):
'''
用户中心
'''
def get(self, request, *args, **kwargs):
return HttpResponse('用户信息')
这样一来,所有的业务都添加了认证,当某一个不需要此认证时,只需将 authentication_classes
设置为空列表即可
如果是匿名用户,可以将其设置为 None
setting.py
REST_FRAMEWORK = {
'UNAUTHENTICATED_USER': None, # 匿名,request.user = None
'UNAUTHENTICATED_TOKEN': None # 匿名,request.auth = None
}