授权回来提示 state 校验失败,日志里打印的 state 是 32 位,实际生成的是 64 位,后半截不见了。回调 URL 里能看到两个问号挨在一起。乍看像缓存或者权限的锅,追下去往往不是。
$cb = add_query_arg(array('action' => 'oauth'), home_url('/login/'));
$state = bin2hex(random_bytes(16));
set_transient('oauth_' . $state, 1, 600);
$url = $auth . '?response_type=code&state=' . $state;
追下去是这么回事:回调地址本身带了查询参数,拼接时又补了一个问号,服务端解析到第一个问号就截断,后面的内容被当成值的一部分。state 里如果自带 & 也会被拆成两个参数。
「OAuth state 截断」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。
能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。
具体做法是,拼回调地址用 add_query_arg 这类函数,别手工接字符串;state 生成后用 urlencode 包一层,避免里面的符号被当分隔符;服务端取值时先看原始 QUERY_STRING,确认参数没被拆开;用一个本身带查询串的回调地址实测,别只在干净路径上测。
验收就看一点,回调 URL 里只有一个问号,日志打印的 state 长度和生成时一致,校验能过。
