You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vert.x FormLoginHandler对接PostgreSQL SqlAuthentication认证失败问题

Vert.x SqlAuthentication 认证报无效用户名密码问题排查

问题现象

使用FormLoginHandler、PostgreSQL配合SqlAuthentication实现用户认证,已确认输入的用户名密码凭据完全正确,仍抛出如下错误:

Jun 15, 2022 1:14:34 PM io.vertx.ext.web.RoutingContext
SEVERE: Unhandled exception in router
io.vertx.ext.web.handler.HttpException: Unauthorized
Caused by: io.vertx.core.impl.NoStackTraceThrowable: Invalid username/password

原有实现代码片段:

SqlAuthenticationOptions sauthopts = new SqlAuthenticationOptions();
sauthopts.setAuthenticationQuery(AUTHENTICATE_QUERY);
SqlAuthentication authenticationProvider = SqlAuthentication.create(sqlClient, sauthopts);

router.route("/secure/*").handler(RedirectAuthHandler.create(authenticationProvider, "/login.html"));

FormLoginHandler formLoginHandler =  FormLoginHandler.create(authenticationProvider);

router.route("/loginhandler").handler(formLoginHandler);  

问题根因&修复方案

当前实现存在3个高频遗漏配置点,按优先级排查即可:

  • 认证查询语句返回列不符合强制规范
    这是90%同类报错的诱因。SqlAuthentication要求自定义的认证查询必须按固定顺序返回3列,缺任意一列都会直接判定凭据无效:
    1. 第一列:数据库存储的用户密码(哈希值或明文)
    2. 第二列:密码使用的哈希算法标识(开发测试用明文可传noop,生产常用pbkdf2、bcrypt等)
    3. 第三列:密码哈希使用的盐值(无盐则传空字符串)
      同时注意PostgreSQL对接时查询的用户名占位符必须用?(位置参数),不能使用命名参数。
      正确的查询示例参考:
    // 注意返回列顺序、占位符写法
    private static final String AUTHENTICATE_QUERY = "SELECT password, 'pbkdf2' AS algo, salt FROM sys_user WHERE username = ?";
    
  • 密码哈希校验策略不匹配
    如果数据库存储的密码哈希算法和查询返回的算法标识不一致,比如数据库存的是MD5哈希值,但查询返回的算法标识写了pbkdf2,哈希比对必然失败。开发阶段临时调试可以把算法标识设为noop,此时会直接做明文比对,快速排除逻辑问题。
  • FormLoginHandler配置缺失
    两个常见问题:一是默认读取表单中name="username"和name="password"的参数作为凭据,如果前端登录表单输入框name属性和默认值不一致,会读不到用户输入的凭据,直接报无效;二是未限定登录路由的请求方法、未配置登录成功跳转地址,会导致异常请求触发认证逻辑、认证完成后无正确响应。需要手动补全配置对齐业务逻辑。

完整可运行参考片段

// 1. 初始化认证配置
SqlAuthenticationOptions authOpts = new SqlAuthenticationOptions();
// 配置符合返回列要求的认证查询,开发调试用noop明文校验
authOpts.setAuthenticationQuery("SELECT password, 'noop' as algo, '' as salt FROM users WHERE username = ?");
SqlAuthentication authProvider = SqlAuthentication.create(sqlClient, authOpts);

// 2. 配置鉴权拦截器
router.route("/secure/*").handler(RedirectAuthHandler.create(authProvider, "/login.html"));

// 3. 配置表单登录处理器
FormLoginHandler loginHandler = FormLoginHandler.create(authProvider)
  .setUsernameParam("username") // 和前端表单输入框name属性对齐
  .setPasswordParam("password") // 和前端表单输入框name属性对齐
  .setDirectLoggedInOKURL("/secure/index"); // 配置登录成功后的默认跳转地址
// 仅接收POST方法的登录提交请求
router.post("/loginhandler").handler(loginHandler);

内容的提问来源于stack exchange,提问作者Lucas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 23:16:01