【问题标题】:Authentication problem using Nginx and Django Rest Framework使用 Nginx 和 Django Rest Framework 的身份验证问题
【发布时间】:2021-02-18 12:46:51
【问题描述】:

在尝试创建基于 Django Rest Framework 的 Web 应用程序时,我们遇到了以下问题:我们的整个应用程序应该并且受到 settings.py 的保护:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication'
    ),

但是对于一个单一的路由(它为前端代码生成提供架构),我们希望有基本的身份验证(test:test@host/special_route)。这个想法是像here一样添加到nginx的路由。我们的 nginx 配置如下所示:

server {
  ...
  location /special_route {
    auth_basic      "API Schema";
    auth_basic_user_file    /etc/nginx/.htpasswd;
  }
}

现在访问此路由时,会显示身份验证弹出窗口并验证密码和用户名,但成功时会显示​​ 404。删除这段代码时,它会显示没有 404,所以我猜这不是 Django 问题。

我尝试向 auth 类添加基本身份验证,重新加载并重新启动服务器并更改 special_route 以避免拼写错误。我什至实验性地删除了该位置并将配置应用于整个服务器,它按预期工作。

【问题讨论】:

  • special_route 你的 django 应用程序的一部分吗?在您的 location 块中没有 proxy_pass 或类似的指令,也许您忽略了它?理解你想要发生的事情有点困难。
  • 阅读this问题和我在下面的评论。
  • @Andrew Backer 感谢您的快速回复!是的,特殊路由是 Django 应用程序的一部分,整个服务器配置都有一个有效的代理通道,所以我把它省略了。
  • @Ivan Wow,这看起来很相似,我明天会检查这个配置!感谢您的回复。
  • 你们俩都是对的,proxy_pass (...) 不是从上面的服务器配置继承的,它与 location / 一起用于配置。你们有人想在这里创建答案还是我应该删除问题?

标签: django nginx django-rest-framework


【解决方案1】:

根据您的评论,special_route 是 django 应用程序的一部分。问题是您需要在该位置内proxy_pass,因为我不认为这是继承的。

upstream django {
    server 127.0.0.1:8000;
}

server {
    listen 80;
    ...

    location /special_route/ {
        auth_basic              "API Schema";
        auth_basic_user_file    /etc/nginx/.htpasswd;

        proxy_pass http://django;
    }

    location / {
        proxy_pass http://django;
    }

代理后,将应用正常的 django 规则。如果您在该路线上的应用程序中使用 Authorization: 标头,我不确定这将如何工作。

看起来您也在使用会话身份验证,因为它在 cookie 中,所以它仍然可以工作。您还可以在 cookie 中添加对 JWT 的身份验证支持,这具有很好的副作用,即没有奇怪的 JS 魔法来发送标头。另外我听说它有一些 XSS 好处,但还没有研究过。

此外,DRF 支持BasicAuthentication,因此您可以直接在应用程序中保护该路由。默认依赖于内置的 django 用户,但您可以覆盖它(注意,这是来自内存,根本没有测试)

class SpecialRouteBasicAuth(BasicAuthentication):
    def authenticate_credentials(self, userid, password, request=None):
        # set these the same as other variables in your settings.py
        u = settings.SPECIAL_USER
        p = settings.SPECIAL_PASS
        
        if userid == u and password == p:
            return (AnonymousUser(), None)
        else:
            raise AuthenticationFailed("Invalid Special User/Pass")
     

class SpecialView():
    permission_classes = [AllowAny]
    authentication_classes = [SpecialRouteBasicAuth]

    def get(self, request):
        # do stuff, but don't rely on request.user

这使用了内置的 AnonymousUser,它具有 is_authenticated 集 False。这意味着视图需要使用AllowAny“公开”。您可以想象一个从该用户继承的新用户类,它只在必要时覆盖is_authenticated 属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-29
    • 2021-09-09
    • 2013-05-03
    • 2019-01-01
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 2015-03-02
    相关资源
    最近更新 更多