GitLab新用户登录遭遇ERR_TOO_MANY_REDIRECTS:从密码过期到数据库修复的实战排查
2026/6/30 1:54:47 网站建设 项目流程

1. 问题现象:诡异的ERR_TOO_MANY_REDIRECTS

最近在给团队部署GitLab 16.2.3时遇到个奇怪现象:管理员root账号登录一切正常,但新建的普通用户首次登录时,浏览器疯狂报错ERR_TOO_MANY_REDIRECTS。页面就像个永动机,在欢迎页和密码修改页之间来回跳转,最终浏览器直接罢工。

这个错误表面看是重定向循环,但背后其实藏着GitLab的密码过期机制。很多新手遇到这个问题会以为是Nginx配置错误,实际上这是GitLab 16.x版本的一个默认安全策略在作祟。我花了三小时排查才发现,原来新建用户的密码默认被标记为"已过期",而系统强制要求修改密码的流程与欢迎页面形成了死循环。

2. 根因分析:密码过期策略的陷阱

2.1 GitLab的默认安全机制

GitLab从14.9版本开始引入了密码过期策略,默认情况下:

  • 新建用户密码立即过期(password_expires_at=当前时间)
  • 首次登录强制跳转修改密码
  • 90天后再次强制修改(可通过配置调整)

这个设计本意是好的,但在某些场景下会翻车。当用户访问欢迎页时,系统发现密码过期就跳转到修改页;修改完成后又跳回欢迎页,结果欢迎页再次检测到"新密码"其实还是"首次设置的密码",于是又判定需要修改... 完美闭环诞生了。

2.2 为什么常规方法失效

我试过这些常见解决方案,全部扑街:

  • 重置密码:root修改用户密码后,登录仍触发循环
  • 调整密码有效期参数:gitlab.rb里找不到相关配置项
  • 提升用户权限:即使用户变成管理员,照样跳转
  • 冻结期限设置:修改password_grace_period根本没用

关键问题在于:这些操作都没真正修改密码的过期状态。通过日志发现,系统始终认为用户密码处于"待修改"状态:

# 查看GitLab日志 sudo tail -f /var/log/gitlab/gitlab-rails/production.log

日志里不断出现:

Redirected to /users/password/edit Completed 302 Found in 2ms

3. 终极解决方案:直捣数据库

3.1 定位PostgreSQL数据库

虽然安装时没特意装PostgreSQL,但GitLab其实自带嵌入式PostgreSQL。通过以下命令确认:

# 查看PostgreSQL数据目录 sudo ls -l /var/opt/gitlab/postgresql/data/ # 检查服务状态 sudo gitlab-ctl status | grep postgres

3.2 数据库操作完整流程

步骤1:进入GitLab的PSQL命令行

sudo gitlab-psql -d gitlabhq_production

步骤2:查询用户信息

-- 查看所有用户 SELECT id,username,name,password_expires_at FROM users; -- 示例输出 id | username | name | password_expires_at ----+----------+-----------+------------------------ 1 | root | Admin | 2 | dev1 | Developer | 2023-12-01 00:00:00

步骤3:修改过期时间

-- 将过期时间设为一个月后 UPDATE users SET password_expires_at = (NOW() + INTERVAL '30 days') WHERE username = 'dev1'; -- 验证修改结果 SELECT username, password_expires_at FROM users WHERE username = 'dev1';

关键细节:

  • 时间格式必须符合PostgreSQL的timestamp标准
  • 建议设置未来时间而非NULL,避免触发其他异常
  • 生产环境建议先备份数据库:sudo gitlab-rake gitlab:backup:create

3.3 后续操作注意事项

  1. 清除浏览器缓存:重定向状态可能被缓存
  2. 模拟用户登录测试
    # 用root模拟用户操作 sudo gitlab-rails console user = User.find_by(username: 'dev1') main_app.user_path(user)
  3. 可选密码重置
    # 通过Rails控制台重置密码 sudo gitlab-rails console user = User.find_by(username: 'dev1') user.password = '新密码' user.save!

4. 预防措施与优化建议

4.1 关闭密码过期策略

如果不需要该功能,可以彻底关闭:

# 修改/etc/gitlab/gitlab.rb gitlab_rails['password_expiration_enabled'] = false sudo gitlab-ctl reconfigure

4.2 自定义过期时间

调整默认90天的策略:

# 修改/etc/gitlab/gitlab.rb gitlab_rails['password_expiration_days'] = 365 sudo gitlab-ctl reconfigure

4.3 新用户创建最佳实践

建议通过API创建用户时直接设置不过期密码:

curl --request POST \ --header "PRIVATE-TOKEN: <your_access_token>" \ --data "email=user@example.com&password=初始密码&skip_confirmation=true&password_expires_at=null" \ "http://gitlab.example.com/api/v4/users"

5. 深度技术原理

5.1 GitLab的认证流程

当用户登录时,系统会依次检查:

  1. 密码是否正确(devise认证)
  2. 密码是否过期(PasswordExpiryCheck中间件)
  3. 是否需强制修改(RequirePasswordChange模块)

这个检查链在app/controllers/application_controller.rb中实现:

before_action :check_password_expiration before_action :required_password_change!

5.2 重定向循环的形成

问题出在app/helpers/authentication_helper.rb:

def store_location_for(resource, location) if resource.require_password_change? super(resource, edit_user_password_path) else super end end

一旦require_password_change?返回true,所有跳转都会被劫持到密码修改页。

6. 替代方案对比

方案操作复杂度需要重启风险等级适用场景
直接改数据库紧急修复
禁用密码过期策略长期解决方案
通过API创建用户自动化部署
使用Omnibus配置新环境预防

7. 常见问题排查

Q:执行gitlab-psql报错"could not change directory"A:这是警告不是错误,实际已连接成功。可以忽略或先执行cd /

Q:UPDATE语句执行但无效A:检查WHERE条件是否准确,建议先用SELECT测试

Q:修改后仍然跳转A:可能是:

  1. 浏览器缓存未清理
  2. 多个用户同名导致更新错记录
  3. PostgreSQL事务未提交(尝试执行COMMIT;

Q:找不到gitlab-psql命令A:完整路径为/opt/gitlab/embedded/bin/gitlab-psql

记得第一次处理这个问题时,我差点以为是Nginx配置问题,重装了三次才发现是密码策略的坑。现在遇到GitLab登录异常,我的排查清单第一位就是检查password_expires_at字段。有些问题看似复杂,找准关键点后其实就几行SQL的事。

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

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

立即咨询