模拟token认证

1.token认证是用来防御跨域攻击的一种手段,就是给用户一段加密的字段,你登陆的时候你拿给我,我给你做一个比较,能对应就通过认证

2.加密字段我们可以使用haslib和time两个模块来实现,这样能够达到实时更新token字段

import hashlib, time 
# 为了用户每次登陆时token都在变所以这里加入time时间是随时都在变的
# 对于设置用户的密码相同的用户或者得到的token一样的情况为了区分它们得给他们加一个唯一权
# 而用户名是唯一的,多以这里引用hashlib(是一种加密算法)对用户名摘要,对token加言
# 定义一个获取随机字符串的函数
def get_random_str(user):
    # 获取随机时间作为随机字符串
    ctime = str(time.time())
    # 对具有唯一性的用户名进行摘要
    md5 = hashlib.md5(bytes(user, encoding="utf8"))
    # 对时间字符串进行加盐
    md5.update(bytes(ctime, encoding="utf8"))
    # 返回加盐后的结果(摘要结果就是当前时间戳+唯一的user对象加言的字符串)
    return md5.hexdigest()
 
3 在登陆的时候获取或者更新token字段
 
# 做一个登录验证的类方法
class LoginView(APIView):
    # 对于有些路由页面是不希望它需要验证相当于白名单,那么我们需要在这个视图类中加一个空的验证组件类
    authentication_classes = []
    permission_classes = []
    throttle_classes = []
    def get(self, request):
        pass  # 这里没有页面返回直接pass
    # 这里主要用到post来进行数据验证
    def post(self, request):
        # 加一个状态码信息,表示返回给页面登录状态
        res = {"status_code": 1000, "msg": "None"}
        try:
            # name = request.POST.get("name")
            # pwd = request.POST.get("pwd")  # 使用原来的方法也能取到数据
            name = request.data.get("name")
            pwd = request.data.get("pwd")
            user = User.objects.filter(name=name, pwd=pwd).first()
            # 要与数据库中的数据作比较, 能取到user就是有该用户允许登录
            if user:
                # 拿到随机的token值然后跟新token 表
                # token 是防跨域攻击的一种防御手段,就是我给你用户一个加密字段,你登录的时候给我就行
                token_str = get_random_str(user.name)  # 将当前的用户名传递过去
                # update_or_create(user=user, defaults={"token":token})
                # 里面两个参数,参数一表示过滤, 表中是否有该对象,有就更新,没有就创建,参数二表示要跟新或者创建对象的值
                token = Token.objects.update_or_create(user=user, defaults={"token": token_str})
                # 将token对象也添加到状态码中(这里要对token字符化否则不能转为json字符串)
                # res["token"] = str(token)
                # 直接使用token_str就行
                res['token'] = token_str
            else:
                res["status_code"] = 1001  # 表示登录失败的状态码
                res["msg"] = "用户登录失败请重新登录或者先注册"
        except Exception as e:
            res["status_code"] = 1002
            res["msg"] = e
        return Response(json.dumps(res))
 
3.再写一个token认证组件然后在你需要的地方加上认证配置
导入自带的认证类,让token认证类继承他
from rest_framework.authentication import BaseAuthentication
# 认证类
class TokenAuth(BaseAuthentication):
    '''token验证类'''
    # 通过看到APIView中的验证源码dispatch中的验证部分我们需要配合写出函数authenticate()
    def authenticate(self, request): 
  # 这里request就是对应源码里的authenticate(self)self
        # 从源码中们可以看出该函数想得到一个元祖里面有两个值self.user, self.auth = user_auth_tuple
        # 我们这里做token 认证将得到的token与数据库中的token作比较
        token_str = request.GET.get("token")
        token_obj = Token.objects.filter(token=token_str).first()
        if not token_obj:
            # 没有就是验证失败,抛出错误
            raise exceptions.AuthenticationFailed("验证失败!")
        else:
            # 认证成功返回两个值(用户名和token对象)
            return (token_obj.user.name, token_obj.token)  # 这里放什么意义不大,看到时候用什么就放什么
 
4 .然后可以在settings文件中配置全局变量,或者在需要验证的类中加入token认证
在settings中配置全局变量
# 给rest_framework创建一个全局认证, 权限, 频率组件的配置, 那么rest_framework会优先从这里拿认证类
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["apt_classes.apt_class.TokenAuth"],  # 这里面放组件的路径
    "DEFAULT_PERMISSION_CLASSES": ["apt_classes.apt_class.SvipPermission"],  # 若果不想做全局的那就注掉该配置,去目标视图中增加权限类
    "PAGE_SIZE": 2  # 配置一下分页每页显示最大数, 如果想局部定制那么自己写一个类继承PageNumberPagination,然后修改相应的变量
}
 
在需要的类中配置token认证
class xxxxView(APIView):
authentication_classes = ["TokenAuth",]
 
5.在地址栏带上?token=xxxxxxxxxxx字符串就能通过验证
posted @ 2020-05-08 14:29  往山上走的人  阅读(506)  评论(0)    收藏  举报