rest_framework认证组件

rest_framework认证组件主要就是用来做登陆校验

使用

第一步建表

class User(models.Model):
    username=models.CharField(max_length=32)
    password=models.CharField(max_length=32)
    user_type=models.IntegerField(choices=((1,'超级用户'),(2,'普通用户'),(3,'二笔用户')))

class UserToken(models.Model):
    user=models.OneToOneField(to='User')###OneToOneField()实质是ForeignKey(unique=True)
    token=models.CharField(max_length=64)

token是什么?

我们之前做验证登录的时候,只要用户端登录成功,服务端就生成一个session(就是一个随机字符串)自己保存起来,再把这个字符串返回给客户端,客户端把这个字符串存起来称为cookie,下次客户端做其他需要登录的操作时只需要把cookie传给服务端和session做比对,只要对的上就是已登陆。(cookie和session都是那个随机字符串,只是在客户端的时候把这个字符串称为cookie,服务端的时候称为session)

但是这么做有个缺点,如果访问服务器的客户很多, 有成千上万个,甚至几十万个,客户端只需要保存自己的cookie就可以了,而服务端就需要保存所有的session,这对服务器说是一个巨大的开销 , 严重的限制了服务器扩展能力。所以有什么办法能让服务端不保存session同样能完成校验呢?有,就是token

我们在服务端保存一个秘密字符串,每次用户登录后返回给客户端的字符串就由:用户的账号+用户的密码+秘密字符串用算法(比如HMAC-SHA256 算法)生成,之后用户做其他操作把这个字符串发给服务端时服务端只需要再用算法解开,就可以拿到账号密码和那个秘密字符串,然后就可以做对比了

ps:秘密字符串就是他们说的密钥 ,用户的账号+用户的密码+密钥用算法生成的字符串就称为token

 

第二步,写一个认证类(继承BaseAuthentication)

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class TokenAuth(BaseAuthentication):
    def authenticate(self, request):
        print('一定会走我')
        token = request.GET.get('token')#用的是request.GET所以前端提交token时要在网址里拼?token=.....
        token_obj = models.UserToken.objects.filter(token=token).first()
        if token_obj:
            return
        else:
            raise AuthenticationFailed('认证失败')
    

第三步,写登录接口和需要登录验证的接口

登录接口

from rest_framework.response import Response
from rest_framework.views import APIView

class Login(APIView):
    
    def get(self,request):
        return render(request,'login.html')

    def post(self,request):
        back_msg={'status':1001,'msg':None}
        print(request.data)

        try:
            name=request.data.get('username')
            password=request.data.get('password')
            user=models.User.objects.filter(username=name,password=password).first()
            if user:
                token=get_random(name)
                models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                back_msg['status']='1000'
                back_msg['msg']='登录成功'
                back_msg['token']=token
            else:
                back_msg['msg'] = '用户名或密码错误'
        except Exception as e:
            back_msg['msg']=str(e)

        return Response(back_msg)

需要登录验证的接口

class Authtest(APIView):
    authentication_classes = [TokenAuth, ]#只要在需要认证的类下面加上authentication_classes = [TokenAuth, ]就可以了
#TokenAuth就是前面的认证类,里面可以放多个认证类;
    def get(self, request):
        return Response('get请求验证成功')

    def post(self, request):
        return Response('post请求验证成功')

 

 

postman试验:

 

因为前面写的是request.GET所以需要在网址里拼?token=....,

只要改成request.data就可以在body里面输入token

同样的想要把token写在header里就需要用request.mata

 

posted @ 2019-07-06 13:16  团子I不哭  阅读(234)  评论(0编辑  收藏  举报