Django 如何用 REMOTE_USER 接入 IIS、CAS 等外部单点登录
2026/9/13 23:43:19 网站建设 项目流程

Django 如何用 REMOTE_USER 接入 IIS、CAS 等外部单点登录

【免费下载链接】djangoThe Web framework for perfectionists with deadlines.项目地址: https://gitcode.com/GitHub_Trending/dj/django

内网应用经常把认证工作交给前置的 Web 服务器或单点登录网关(如 IIS + Integrated Windows Authentication、Apache +mod_authnz_ldapCASWebAuthmod_auth_sspi等),Django 本身不处理密码,只接收认证后的用户名。这类方案下,服务器会把认证后的用户名放入REMOTE_USER:WSGI 部署中它出现在request.METAREMOTE_USER键,ASGI 部署中则通过 HTTP 头传递,对应request.METAHTTP_REMOTE_USER键。Django 提供RemoteUserMiddleware(或PersistentRemoteUserMiddleware)与RemoteUserBackend来处理这个值,实现自动登录。

官方操作文档见 docs/howto/auth-remote-user.txt,后端 API 说明见 docs/ref/contrib/auth.txt。

基本配置

两步改动都写在项目settings中。

第一步:添加中间件。django.contrib.auth.middleware.RemoteUserMiddleware加入MIDDLEWARE,且必须放在django.contrib.auth.middleware.AuthenticationMiddleware之后:

MIDDLEWARE = [ "...", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.auth.middleware.RemoteUserMiddleware", "...", ]

这个顺序有硬性要求:如果AuthenticationMiddleware没在前面(即request上还没有user属性),RemoteUserMiddleware会抛出ImproperlyConfigured,提示在 MIDDLEWARE 中把AuthenticationMiddleware插到它前面。

第二步:替换认证后端。AUTHENTICATION_BACKENDS中用RemoteUserBackend替换ModelBackend

AUTHENTICATION_BACKENDS = [ "django.contrib.auth.backends.RemoteUserBackend", ]

这样配置后,RemoteUserMiddleware会从request.META['REMOTE_USER'](ASGI 下为request.META['HTTP_REMOTE_USER'])取出用户名,通过RemoteUserBackend认证并自动登录该用户。

RemoteUserBackend继承自ModelBackend,所以权限检查逻辑(has_permget_all_permissions等)与默认后端一致。默认行为有两点要注意:

  • create_unknown_user默认为True:数据库中不存在的用户名会被自动创建为User对象;
  • is_active=False的用户不允许认证。如需放行非激活用户,改用django.contrib.auth.backends.AllowAllUsersRemoteUserBackend

保留 admin 登录通道的可选方案

只配置RemoteUserBackend时,默认ModelBackend被禁用,意味着如果某次请求没有REMOTE_USER值,用户无法登录——包括通过 Django admin 界面登录。如果还需要保留密码登录作为后备,把两个后端都放进列表即可:

AUTHENTICATION_BACKENDS = [ "django.contrib.auth.backends.RemoteUserBackend", "django.contrib.auth.backends.ModelBackend", ]

文档明确说明:当REMOTE_USER不存在时回退到ModelBackend,可以解决无法登录 admin 的问题。

另外要清楚边界:contrib.admin的用户管理界面和createsuperuser命令操作的是数据库里存储的用户,与AUTHENTICATION_BACKENDS无关,它们不会和 remote user 流程联动。

使用自定义 HTTP 头(可选分支)

如果你的认证机制传递的不是REMOTE_USER而是自定义 HTTP 头,可以子类化RemoteUserMiddleware并设置header属性为对应的request.META键。例如文档中的例子(放在mysite/middleware.py):

from django.contrib.auth.middleware import RemoteUserMiddleware class CustomHeaderRemoteUserMiddleware(RemoteUserMiddleware): header = "HTTP_AUTHUSER"

然后在MIDDLEWARE中用这个自定义中间件替换RemoteUserMiddleware

这里有一条必须遵守的安全约束(文档以 warning 形式强调):RemoteUserMiddleware绝不能部署在客户端可以自己提供该头的配置中。必须确保 Web 服务器或反向代理基于认证检查结果来设置或剥离该头,绝不允许终端用户提交伪造的头值。由于X-Auth-UserX-Auth_User这类头在request.META中都会归一化为HTTP_X_AUTH_USER,还要确认 Web 服务器不允许用下划线替代连字符来伪造头。

两个环境的差异:

  • WSGI:默认配置(header = "REMOTE_USER")下上述警告不适用,因为request.META中不以HTTP_开头的键只能由 WSGI 服务器设置,HTTP 请求头无法直接写入;
  • ASGI:所有配置下该警告都适用,因为 ASGI 没有等价于 WSGI environ 的可信值通道。ASGI 部署使用此中间件时必须配合文档所述的反向代理。

只在登录页做外部认证:PersistentRemoteUserMiddleware

RemoteUserMiddleware假设每个已认证请求都携带REMOTE_USER。这在 Basic HTTP Auth(htpasswd之类)下是合理的,但对 Negotiate(GSSAPI/Kerberos)这类开销较大的认证方式,前端服务器通常只对一两个登录 URL 启用认证,登录成功后由应用自己维持会话。

PersistentRemoteUserMiddleware正是为这种场景设计的:它会保持认证会话有效,直到用户显式登出;即使请求中找不到request.META键也不会强制注销(其实现上就是把force_logout_if_no_header设为False)。它可以在上面的配置中作为RemoteUserMiddleware的直接替换使用,中间件位置与后端配置不变。

验证接入是否生效

仓库自带的测试 tests/auth_tests/test_remote_user.py 展示了核对方式,可作为验证思路:

  1. 向视图发起不带REMOTE_USER的请求,确认response.context["user"].is_anonymousTrue,且User.objects.count()不增加(未提供用户名时不会创建用户);
  2. 带上REMOTE_USER头再次请求,确认request.user已认证为对应用户,且默认情况下新用户名会在数据库中被自动创建。

测试中 WSGI 客户端通过 environ 直接传入REMOTE_USER值,ASGI 客户端则通过headers传递——这与上文两种环境下request.META键名不同的说明一致。生产环境则应由你的 Web 服务器(IIS、Apache 模块等)在认证后注入该值,Django 侧只负责消费。

需要更多控制时

若默认行为不够用(例如用户名需要清洗 LDAP DN、认证后要按外部目录属性设置用户组),可以继承RemoteUserBackend并重写clean_username(username)configure_user(request, user, created=True)等方法;configure_user在用户取出或创建后立即调用,created参数可区分是首次创建还是同步已有用户,适合做本地与外部系统的属性同步(如按 LDAP 属性设置用户组)。这些方法的语义见 docs/ref/contrib/auth.txt 中RemoteUserBackend一节,自定义后端思路在 docs/howto/auth-remote-user.txt 中也有说明。

限制与边界

  • 认证的最终控制权在前端:用户名被认为是可信的,Django 不校验密码。因此头防伪造是部署侧的硬前提;
  • is_active=False的用户默认被拒绝,用AllowAllUsersRemoteUserBackend放行是显式选择;
  • admin 界面与createsuperuser不感知 remote user 流程,它们管理的是数据库用户;
  • ASGI 部署必须走反向代理注入/剥离认证头,不能用默认配置直接暴露。

【免费下载链接】djangoThe Web framework for perfectionists with deadlines.项目地址: https://gitcode.com/GitHub_Trending/dj/django

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询