美文网首页
59.1-Django认证、中间件和jwt过期

59.1-Django认证、中间件和jwt过期

作者: BeautifulSoulpy | 来源:发表于2020-08-16 16:05 被阅读0次
    人生,方向比努力更重要。学会忘掉过去,过去再美再辉煌,终究代表的是过去的自己!

    总结:

    1. 框架其实就是 流程、套路;
    logininfo
    1. Django的认证

    django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:
    1、authenticate(**credentials)
    提供了用户认证,即验证用户名以及密码是否正确
    user = authentica(username='someone',password='somepassword')
    2、login(HttpRequest, user, backend=None)
    该函数接受一个HttpRequest对象,以及一个认证了的User对象
    此函数使用django的session框架给某个已认证的用户附加上session id等信息。
    3、logout(request) 本次使用
    注销用户
    该函数接受一个HttpRequest对象,无返回值。
    当调用该函数时,当前请求的session信息会全部清除
    该用户即使没有登录,使用该函数也不会报错
    还提供了一个装饰器来判断是否登录django.contrib.auth.decorators.login_required
    本项目使用了无session机制,且用户信息自己建表管理,所以,认证需要自己实现。

    2. 中间件技术Middleware

    官方定义,在Django的request和response处理过程中,由框架提供的hook钩子
    中间件技术在1.10后发生了改变,我们当前使用1.11版本,可以使用新的方式定义。
    参看 https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware

    # 要在setting的MIDDLEWARE中注册;
    class AuthMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
            # One-time configuration and initialization.
    
        def __call__(self, request):
            # Code to be executed for each request before
            # the view (and later middleware) are called.
            print(request,'++++++++++++++++++++++++++')
            token = request.META.get('HTTP_JWT',None)
            print(token)
            # 统计IP验证 : 1分钟1000次以上;  使用字典记录次数 =》 redis kv; 调shell - 防火墙;
    
    
            response = self.get_response(request)
    
            # Code to be executed for each request/response after
            # the view is called.
    
            return response
    

    但是, 这样所有的请求和响应都拦截, 我们还得判断是不是访问的想要拦截的view函数, 所以, 考虑其他方法。
    中间件有很多用途, 适合拦截所有请求和响应。例如 浏览器端的IP是否禁用、UserAgent分析、异常响应的统一处理。

    3. 装饰器*

    在需要认证的view函数上增强认证功能,写一个装饰器函数。谁需要认证,就在这个view函数上应用这个装饰器。

    AUTH_EXPIRE = 8 * 60 * 60  # 8小时过期
    
    def authenticate(view):
        def wrapper(request: HttpRequest):
            # 自定义header jwt
            payload = request.META.get('HTTP_JWT')  # 会被加前缀HTTP_且全大写
            if not payload:  # None没有拿到,认证失败
                return HttpResponse(status=401)
            try:  # 解码
                payload = jwt.decode(payload, settings.SECRET_KEY, algorithms=['HS256'])
                print(payload)
            except:
                return HttpResponse(status=401)
    
            # 验证过期时间
            current = datetime.datetime.now().timestamp()
            if (current - payload.get('timestamp', 0)) > AUTH_EXPIRE:
                return HttpResponse(status=401)
            print('-' * 30)
            try:
                user_id = payload.get('user_id', -1)
                user = User.objects.filter(pk=user_id).get()
                request.user = user  # 如果正确,则注入user
                print('-' * 30)
            except Exception as e:
                print(e)
                return HttpResponse(status=401)
            
            ret = view(request)  # 调用视图函数
            # 特别注意view调用的时候,里面也有返回异常
            return ret
        return wrapper
    
    @authenticate  # 很自由的应用在需要认证的view函数上
    def test(request: HttpRequest):
        return HttpResponse('test')
    
    from django.http import JsonResponse,HttpRequest,HttpResponseBadRequest
    import simplejson,jwt,bcrypt,datetime
    from .models import User
    from django.db.models import Q
    from django.conf import settings
    
    AUTH_EXPIRE = 8*60*60
    
    def gen_token(user_id):  # 生成令牌;
        key = settings.SECRET_KEY
        return jwt.encode({'user_id':user_id,
                           'timestamp':int(datetime.datetime.now().timestamp() + AUTH_EXPIRE)  # 结束时间
                           },key,'HS256').decode()
    
    # register
    def reg(request:HttpRequest):
        print(request.body)
    
        try:
            payload = simplejson.loads(request.body)  # 用户数据Json化 提交;
            print(type(settings))
    
            email = payload['email']      # 提取内容
            query = User.objects.filter(email=email)   # 看email是否已经存在;
            if query.first():  # 查一下: email 如果存在,则return error;
                print('============================')
                return HttpResponseBadRequest('用户名已存在')
    
            # 用户名不存在,继续向下;
            name = payload['name']   #
            password = payload['password']
    
            user = User()
            user.email = email
            user.name = name
            user.password = bcrypt.hashpw(password.encode(),bcrypt.gensalt())   # 密码采用bcrypt加密;盐一直在变,强加密;
    
            try:
                user.save()    #保存到数据库test,唯一键约束
                return JsonResponse({
                    'user_id':user.id
                })   # 保存数据后返回一个令牌数据回去;
            # 可以返回user_id status=201(注册成功 重新登录) 或者 token(登录)
    
            except Exception as e:
                return JsonResponse({'reason':'asdaf'},status=400)
        except Exception as e:
            print(e)
            return HttpResponseBadRequest('参数错误')
    
    
    def login(request:HttpRequest):
        try:
            payload = simplejson.loads(request.body)
            email = payload['email']
            password = payload['password']
    
            user = User.objects.filter(email=email).first()
            if user:  # 登录成功,返回信息
                if bcrypt.checkpw(password.encode(),user.password.encode()):
                    token = gen_token(user.id)
                    res = JsonResponse({
                        'user':{
                            'user_id': user.id,
                            'name': user.name,
                            'email': user.email
                        }, 'token': token
                    })
    
                    res.set_cookie('jwt',token)  # 演示 如何 set_cookie
    
                    return res
                else:
                    return HttpResponseBadRequest('登录失败3')
            else:
                return HttpResponseBadRequest('登录失败1')
    
        except Exception as e:   # 记录登录日志;
            print(e)
            return HttpResponseBadRequest('登录失败2')
    
    # 谁认证就给谁加装饰器;
    def auth(view_func):
        def wrapper(request:HttpRequest):
            token = request.META.get('HTTP_JWT', None)  # 拿到http_jwt 字典的值
            # print(list(filter(lambda x: x.lower().endswith('jwt'),meta)))  #查询 http_jwt
            print(token)
            if not token: #  认证失败
                return HttpResponseBadRequest()
    
            key = settings.SECRET_KEY
            try:
                print('=============================')
                payload = jwt.decode(token, key, algorithms=['HS256'])  # 解失败,被改过;接成功;没改过;
                # dt = payload['timestamp']
                # current = datetime.datetime.now().timestamp()
                #
                # if (current - dy) > AUTH_EXPIRE:    # exp check 过期检查;
                #     return HttpResponseBadRequest('expire')
                # user_id = payload.get('user_id',-1)
                user = User.objects.filter(pk=payload['user_id']).first()   # 查询一次数据库;
                # user = User.objects.filter(pk=payload['user_id']).filter(isactive=True).first()
    
                if user: # 拿到user,
                    request.user = user  #request 动态添加属性;
                    ret = view_func(request)
    
                    return ret
                else:
                    return HttpResponseBadRequest('1用户名密码错误')
            except jwt.ExpiredSignatureError as e:
                print(e)
                return HttpResponseBadRequest('jwt过期')
            except Exception as e:
                print(e)
                return HttpResponseBadRequest('用户名密码错误')
        return wrapper
    
    @auth        # 认证拦截
    def show(request):          # 方法的使用方式各不相同;
        # print(request.user,'---------------------------')
        return JsonResponse({'status':'ok'})
    
    # 要在setting的MIDDLEWARE中注册;
    class AuthMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
            # One-time configuration and initialization.
    
        def __call__(self, request):
            # Code to be executed for each request before
            # the view (and later middleware) are called.
            print(request,'++++++++++++++++++++++++++')
            token = request.META.get('HTTP_JWT',None)
            print(token)
            # 统计IP验证 : 1分钟1000次以上;  使用字典记录次数 =》 redis kv; 调shell - 防火墙;
    
    
            response = self.get_response(request)
    
            # Code to be executed for each request/response after
            # the view is called.
    
            return response
    
    

    相关文章

      网友评论

          本文标题:59.1-Django认证、中间件和jwt过期

          本文链接:https://www.haomeiwen.com/subject/hcbtjktx.html