decrators.py 3.95 KB
# coding: utf-8

import django.http
from functools import wraps
from django.conf import settings
from django.utils.decorators import available_attrs
from django.shortcuts import resolve_url
from django.utils.six.moves.urllib.parse import urlparse

def weapp_django_logout(request, response):
    assert isinstance(request, django.http.HttpRequest)
    assert isinstance(response, django.http.HttpResponse)
    # 请求统一认证登出
    response.delete_cookie('pt')
    response.delete_cookie('pu')
    response.delete_cookie('username')
    return response

def weapp_logout(func=weapp_django_logout):
    """
    Django登出视图函数装饰器
    :param func: 处理登出逻辑的函数,接受request和response两个参数
    :return:
    """
    return auth_decorator_factory(func)


def auth_decorator_factory(func=None):
    """
    登录登出装饰器工厂函数,允许用户自定义外部登录登出函数
    :param func:
    :return:
    """

    def decorator(view_func):
        @wraps(view_func)
        def _wrapped_view(request, *args, **kwargs):
            response = view_func(request, *args, **kwargs)
            if func:
                func(request, response)
            return response

        return _wrapped_view

    return decorator

import json

from django.http import JsonResponse


class QCCRJsonResponse(JsonResponse):
    """
    封装了返回码和信息的JsonResponse类
    """
    def __init__(self, obj=None, code=200, msg="success", status=200, **kwargs):
        data = {"code": code, "msg": msg, "result": json.loads(obj) if isinstance(obj, (str, unicode)) else obj}
        super(QCCRJsonResponse, self).__init__(data=data, status=status, **kwargs)


class QCCRErrorResponse(QCCRJsonResponse):
    """
    请求错误
    """
    def __init__(self, obj=None, code=400, msg="failure", status=400, **kwargs):
        super(QCCRErrorResponse, self).__init__(obj=obj, code=code, msg=msg, status=status, **kwargs)

def user_passes_test(test_func, login_url=None,
                     redirect_field_name=getattr(settings, "QCCR_REDIRECT_FIELD_NAME", 'redirect')):
    """
    本装饰器通过test_func函数,检查views是否通过相应的检测,未通过则跳转到登录页面;test_func函数接受user对象作为参数,通过则返回True
    """

    def decorator(view_func):
        @wraps(view_func, assigned=available_attrs(view_func))
        def _wrapped_view(request, *args, **kwargs):
            if test_func(request.user):
                return view_func(request, *args, **kwargs)
            # 如果未通过检查,且为ajax请求,返回403
            if request.is_ajax():
                return QCCRErrorResponse(code=403, msg="用户身份检查失败", status=403)
            # 非ajax请求,跳转到登录页面
            path = request.build_absolute_uri()
            resolved_login_url = resolve_url(login_url or getattr(settings, "QCCR_LOGIN_URL", '/login/'))
            login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
            current_scheme, current_netloc = urlparse(path)[:2]
            if ((not login_scheme or login_scheme == current_scheme) and
                    (not login_netloc or login_netloc == current_netloc)):
                path = request.get_full_path()
            from django.contrib.auth.views import redirect_to_login
            return redirect_to_login(path, resolved_login_url, redirect_field_name)

        return _wrapped_view

    return decorator


def weapp_login_required(function=None,
                        redirect_field_name=getattr(settings, "QCCR_REDIRECT_FIELD_NAME", 'redirect'),
                        login_url=None):
    """
    登录状态检查装饰器,如果未登录,则直接跳转到登录页面
    """
    actual_decorator = user_passes_test(
        lambda u: u.is_authenticated(),
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator