PHP实现Discord OAuth2登录回调后无法获取token问题求助
Discord OAuth2登录问题修复方案
核心问题排查
- apiRequest函数逻辑顺序错误:函数内初始化curl后多执行了一次无用的
curl_exec,此时还未配置POST参数和请求头,导致请求Discord接口时参数缺失,无法正常获取token。 - 缺少错误校验逻辑:获取token请求后没有判断接口返回是否合法,当Discord返回错误信息(如密钥不匹配、回调地址不一致)时,直接读取不存在的
access_token属性会导致session赋值为空。 - 代码顺序错误:未定义
$user变量时就提前在script标签中输出该变量的属性,可能抛出PHP警告干扰header跳转逻辑。 - 可选优化:Discord官方API域名已从
discordapp.com迁移到discord.com,建议更新接口地址避免后续旧域名失效。
修复后的代码
<?php ini_set('display_errors', 1); ini_set('display_startup_errors', 1); ini_set('max_execution_time', 300); error_reporting(E_ALL); define('OAUTH2_CLIENT_ID', 'XXXXXXXXXXXXXXXXXXXXXX'); // 替换为你的客户端ID define('OAUTH2_CLIENT_SECRET', 'XXXXXXXXXXXXXXXXXXXXXX'); // 替换为你的客户端密钥 $authorizeURL = 'https://discord.com/api/oauth2/authorize'; $tokenURL = 'https://discord.com/api/oauth2/token'; $apiURLBase = 'https://discord.com/api/users/@me'; session_start(); // 登录逻辑 if(get('action') == 'login') { header('Location: https://discord.com/api/oauth2/authorize?client_id=873917693953191946&redirect_uri=http%3A%2F%2Fbouncerbot.go-atcode.com%2Fauth.php&response_type=code&scope=identify%20email%20connections%20guilds%20gdm.join%20guilds.join%20rpc%20rpc.notifications.read%20rpc.voice.read%20rpc.voice.write'); die(); } // 回调处理逻辑 if(get('code')) { $token = apiRequest($tokenURL, array( "grant_type" => "authorization_code", 'client_id' => OAUTH2_CLIENT_ID, 'client_secret' => OAUTH2_CLIENT_SECRET, 'redirect_uri' => 'http://bouncerbot.go-atcode.com/auth.php', 'code' => get('code') )); // 增加返回值判断 if(isset($token->access_token)){ $_SESSION['access_token'] = $token->access_token; $_SESSION['logout_token'] = $token->access_token; } header('Location: ' . $_SERVER['PHP_SELF']); die(); } // 登录状态展示 if(session('access_token')) { $user = apiRequest($apiURLBase); // 把script标签移到这里,避免调用未定义变量 echo '<script> console.log('.json_encode($user->username).')</script>'; echo '<h3>Logged In</h3>'; echo '<h4>Welcome, ' . $user->username . '</h4>'; echo '<pre>'; print_r($user); echo '</pre>'; } else { echo '<h3>Not logged in</h3>'; echo '<p><a href="?action=login">Log In</a></p>'; } // 登出逻辑 if(get('action') == 'logout') { $params = array( 'access_token' => session('logout_token') ); header('Location: https://discord.com/api/oauth2/token/revoke' . '?' . http_build_query($params)); die(); } // 修复后的apiRequest函数 function apiRequest($url, $post=FALSE, $headers=array()) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); if($post) { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post)); } $headers[] = 'Accept: application/json'; if(session('access_token')) { $headers[] = 'Authorization: Bearer ' . session('access_token'); } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); // 增加curl错误判断 if(curl_errno($ch)){ error_log('CURL错误: ' . curl_error($ch)); return null; } curl_close($ch); return json_decode($response); } function get($key, $default=NULL) { return array_key_exists($key, $_GET) ? $_GET[$key] : $default; } function session($key, $default=NULL) { return array_key_exists($key, $_SESSION) ? $_SESSION[$key] : $default; } ?>
额外校验项
如果修复后仍有问题,请检查以下配置:
- Discord开发者后台中填写的回调地址必须和代码中
redirect_uri完全一致,包括http/https协议、域名、路径、端口都不能有差异 - 确认使用的客户端ID和客户端密钥没有填错,没有多余的空格或特殊字符
- 确认服务器可以正常访问Discord的API接口,没有被防火墙拦截
内容的提问来源于stack exchange,提问作者Conta
相关产品推荐
相关产品推荐

