单点登录异常,出现Bad Request (400)

单点登录异常,出现Bad Request (400)

[2026-08-27 08:58:10] [WARNING] django.request:253 log_response The request's session was deleted before the request completed. The user may have logged out in a concurrent request, for example.: /
Traceback (most recent call last):
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/contrib/sessions/backends/db.py", line 127, in save
    obj.save(
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/db/models/base.py", line 902, in save
    self.save_base(
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/db/models/base.py", line 1008, in save_base
    updated = self._save_table(
              ^^^^^^^^^^^^^^^^^
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/db/models/base.py", line 1142, in _save_table
    raise DatabaseError("Forced update did not affect any rows.")
django.db.utils.DatabaseError: Forced update did not affect any rows.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/contrib/sessions/middleware.py", line 59, in process_response
    request.session.save()
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/contrib/sessions/backends/db.py", line 136, in save
    raise UpdateError
django.contrib.sessions.backends.base.UpdateError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/utils/deprecation.py", line 122, in __call__
    response = self.process_response(request, response)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/seafile/seafile-server-13.0.12/seahub/thirdpart/django/contrib/sessions/middleware.py", line 61, in process_response
    raise SessionInterrupted(
django.contrib.sessions.exceptions.SessionInterrupted: The request's session was deleted before the request completed. The user may have logged out in a concurrent request, for example.

这段堆栈不是 SSO 协议本身返回的具体错误,而是 Seafile 在完成 SSO 回调、准备保存 Django 会话时,发现该会话记录已被另一请求删除:

SessionInterrupted: The request's session was deleted before the request completed

最常见原因是同一浏览器把不同系统的会话 Cookie 混用了。例如 Seafile 和 SeaTable/另一套 Seafile/其他 Django 应用使用相同主域名,即使端口不同,Cookie 仍可能共享;新的请求会覆盖或删除旧 sessionid,从而导致 SSO 回调保存会话失败。社区已有相同场景:同域名不同端口的 Seafile 与 SeaTable 因都使用 sessionid 而相互踢出登录。

建议按以下顺序排查

  1. 浏览器侧验证

    • 使用无痕窗口重试;
    • 清除 Seafile 域名下所有 Cookie(尤其 sessionid、SSO/IdP 域名 Cookie);
    • 确保没有同时打开同主域名下的 SeaTable、测试环境、旧 Seafile 等站点。
  2. 检查是否存在 Cookie 冲突

    • 确认 Seafile 与其他应用是否使用相同域名或父域名,例如:
      • seafile.example.com
      • seatable.example.com
      • sso.example.com
    • 若多个应用共用 Cookie 名 sessionid 且 Cookie Domain 被设置为 .example.com,应让它们使用不同会话 Cookie 名,或隔离 Cookie Domain。
    • 不建议直接修改 seahub/thirdpart/django/conf/global_settings.py,升级会覆盖。应优先在持久化的 conf/seahub_settings.py 中覆盖,例如:
      SESSION_COOKIE_NAME = 'seafile_sessionid'
      
      配置后重启 Seafile/Seahub,并让用户清除旧 Cookie 后再试。
  3. 核对 SSO 回调地址与外部访问地址

    • SSO IdP 中登记的 ACS/Callback URL 必须与用户实际访问的 Seafile 外部 URL 完全一致,包括协议、域名、端口和路径。
    • 若经 Nginx、负载均衡、FRP 或 NAT 访问,需确保 Seafile 配置的是用户浏览器实际使用的公网 URL/端口;相关部署案例也要求 SEAFILE_SERVER_HOSTNAME 与浏览器访问地址一致。
  4. 如报错页实际为 CSRF/Origin 类 400/403

    • conf/seahub_settings.py 中加入实际的 HTTPS 外部地址:
      CSRF_TRUSTED_ORIGINS = [
          'https://seafile.example.com',
      ]
      
    • 该配置曾用于解决反向代理后 Origin checking failed 的登录问题。
  5. 检查反向代理与多节点

    • 代理必须保留 HostX-Forwarded-Proto 等头,且 SSO 过程中不能在 HTTP/HTTPS、内外网域名或不同节点间跳转。
    • 若 Seafile 有多台 Web/Seahub 节点,所有节点必须连接同一会话数据库,并使用一致的配置;同时需要会话粘滞或共享会话机制,否则也可能出现回调请求落到不同节点的问题。

优先建议:先用无痕模式验证;如果恢复正常,基本可确认是 Cookie/会话冲突。随后为 Seafile 设置独立的 SESSION_COOKIE_NAME,清掉旧 Cookie 并重启服务。

我试过使用 keycloak 配置 openid 实现 seafile 的单点登录,你可以参考 https://wiki.anas365.com/spaces/VirtualReal/pages/84246531/docker-seafile+和+seatable+整合+keycloak+实现单点登录