用户登录认证
问题 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
- }
来源: http://www.bubuko.com/infodetail-2967609.html