Django 实现默认的 login_required

Background

我们在使用 Django 做 Api 开发时,基本所有接口都需要认证。这种情况下,如果使用 Django
原生的 login_required 就会显得非常麻烦,每个接口上都需要添加这个装饰器。

因此,需要能够实现一个默认的 『login_required』,默认将所有接口都加上登录校验,而只将一些特殊的接口例外。

Solution

  1. 使用 Django Middleware 来实现登录校验

    from django.http.response import HttpResponseForbidden
    from django.conf import settings
    
    class LoginRequiredMiddleWare(object):
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            # 判断是否已经登录。这里依赖于 SessionMiddleware 
            # 和 AuthenticationMiddleWare 做自动认证
            if hasattr(request, 'user') and not request.user.is_authenticated:
                ignore = False
                for prefix in settings.AUTH_FREE_URL_PREFIX:
                    if request.path.startswith(prefix):
                        ignore = True
                        break
                if ignore is False:
                    # 如果未登录且没有设置忽略,则直接返回 503
                    return HttpResponseForbidden()
    
            # 正常处理请求
            response = self.get_response(request)
            return response
    
        def process_exception(self, request, exception):
            """ automatically handle exception in get response """
            pass
    
  2. 修改配置文件 settings.py,配置需要忽略的 url

    AUTH_FREE_URL_PREFIX = [
        '/account/user/login',
    ]
    

    从 Middleware 的实现可以看出,装饰器是在 get_response 里面的,因此无法像 login_reqired 那样实现
    一个 login_free。所以可以选择这种配置文件的形式。

Summary

  1. Dango Middleware 可以实现对 Request 的统一处理
  2. Middleware 的 process_exception 方法,可以实现异常的统一处理。这样在 Django App 的逻辑代码中, 就可以直接 raise exception,避免每个地方都单独处理异常 Response

Reference

  1. Dango Middleware