认证
任何的项目都需要认证, 当用户输入了用户名和密码, 验证通过, 代表用户登录成功
那 HTTP 请求是无状态的, 下次这个用户再请求, 是不可能识别这个用户是否登录的
就要有自己的方式来实现这个认证, 用户登录成功以后, 生成一个随机字符串, 以后这个用户再请求, 都要携带这个随机字符串.
就可以根据这个字符串进行判断这个用户是否登录, 目的是前端发送请求的时候带过来就可以, 以前的 cookie,session 是的一种解决方案, 认证的时候也用过 token 的这种解决方案.
token
用户登录成功后, 生成一个随机字符串 token 给前端返回
那么前端以后都携带这个 token 来访问这样只需要鉴别这个 token 来做认证
前端如果发送请求把 token 放在请求头中看下的认证要怎么写
序列化注册数据
测试的时候用的重写 create 方法, 真正开发前端传过来的就是加密后的密文密码
- from rest_framework import serializers
- from Course.models import Account
- import hashlib
- class RegisterSerializer(serializers.ModelSerializer):
- class Meta:
- model = Account
- fields = "__all__"
- def create(self, validated_data):
- pwd = validated_data["pwd"]
- pwd_salt = "luffy_password" + pwd # 加盐处理
- md5_str = hashlib.md5(pwd_salt.encode()).hexdigest()
- user_obj = Account.objects.create(username=validated_data["username"], pwd=md5_str)
- return user_obj
Login/serializers.py
注册, 登录的视图
from rest_framework.views import APIView from rest_framework.response import Response from .serializers import RegisterSerializer from utils.base_response import BaseResponse from Course.models import Account from utils.redis_pool import POOL import Redis import uuid from utils.my_auth import LoginAuth from utils.geetest import GeetestLib from django.http import HttpResponse import JSON # Create your views here. class RegisterView(APIView): def post(self, request): res = BaseResponse() # 实例化响应类 # 用序列化器做校验 ser_obj = RegisterSerializer(data=request.data) if ser_obj.is_valid(): ser_obj.save() res.data = ser_obj.data else: res.code = 1020 res.error = ser_obj.errors return Response(res.dict) class LoginView(APIView): def post(self, request): res = BaseResponse() username = request.data.get("username", "") pwd = request.data.get("pwd", "") user_obj = Account.objects.filter(username=username, pwd=pwd).first() if not user_obj: res.code = 1030 res.error = "用户名或密码错误" return Response(res.dict) # 用户登录成功生成一个 token 写入 Redis # 写入 Redis token : user_id conn = Redis.Redis(connection_pool=POOL) # 从连接池获取一个连接 try: token = uuid.uuid4() conn.set(str(token), user_obj.id, ex=10000) # conn.set(str(token), user_obj.id) # str(token) 用作 key res.data = token except Exception as e: print(e) res.code = 1031 res.error = "创建令牌失败" return Response(res.dict)
Login/views.py
class BaseResponse(object): """ 封装响应的类 """ def __init__(self): self.code = 1000 self.data = None self.error = None @property def dict(self): return self.__dict__ # 返回字典
utils/base_response.py
认证器
http 头部发送的字段信息 key:value
在服务器接受时, 需要加上前缀 (并且大写) 例如 HTTP_KEY , 通过 request.META.get(HTTP_KEY) 获取值
import Redis from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from .redis_pool import POOL from Course.models import Account CONN = Redis.Redis(connection_pool=POOL) class LoginAuth(BaseAuthentication): def authenticate(self, request): # 从请求头中获取前端带过来的 token. 或者跟前端商量好 token = request.META.get("HTTP_AUTHENTICATION", "") # print(request.META) # print(token) if not token: raise AuthenticationFailed("没有携带 token") # 去 Redis 比对 user_id = CONN.get(str(token)) # get 没有的值返回 None if user_id == None: raise AuthenticationFailed("token 过期") # 重新登录设置 token user_obj = Account.objects.filter(id=user_id).first() return user_obj, token
utils/my_auth.py
用到的 Redis 连接池
import Redis POOL = Redis.ConnectionPool(host="127.0.0.1", port=6379, decode_responses=True, max_connections=10)
utils/redis_pool.py
注册用户测试
测试发送密码时为密文. 前端传过来, 后端加密后再与数据库中的比对
以 token 为 key 存放在 Redis 中, 登录成功后返回生成的 token 数据(有有效期的), 下次登录时携带上. 后端以传过来的 token 去 reids 中找, 能找到就拿到用户信息, 不能就说明过期需要重新登录, 或者 token 不存在.
来源: http://www.bubuko.com/infodetail-2975270.html