">登录 * 回跳页开头: if ($user = uc_handle_sso()) { /* $user['uid'],$user['username'] 建立本地会话 *\/ } * 账号密码验证: $r = uc_login($u, $p); // 通过即自动绑定,全平台通行 * 平台内注册: $r = uc_register($u, $p); * 退出登录: uc_logout($token); */ $_UC_CFG = ['url' => '', 'app_id' => '', 'app_key' => '']; function uc_init($uc_url, $app_id, $app_key) { global $_UC_CFG; $_UC_CFG['url'] = rtrim($uc_url, '/'); $_UC_CFG['app_id'] = $app_id; $_UC_CFG['app_key'] = $app_key; } /** 签名:sha256( app_id | app_key | ts | md5(json(data)) ),data 须 ksort */ function uc_sign($ts, array $data) { global $_UC_CFG; ksort($data); return hash('sha256', $_UC_CFG['app_id'] . '|' . $_UC_CFG['app_key'] . '|' . $ts . '|' . md5(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))); } /** 调用中心 API,返回数组(ok=true/false) */ function uc_api($action, array $data = []) { global $_UC_CFG; if (!$_UC_CFG['url']) { return ['ok' => false, 'error' => 'SDK 未初始化,请先 uc_init()', 'code' => 'no_init']; } $ts = time(); $data['app_id'] = $_UC_CFG['app_id']; $data['action'] = $action; $data['ts'] = $ts; $data['sign'] = uc_sign($ts, array_diff_key($data, ['action' => 1, 'ts' => 1, 'sign' => 1])); $body = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); $ch = curl_init($_UC_CFG['url'] . '/api.php'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => true, ]); $resp = curl_exec($ch); $err = curl_error($ch); curl_close($ch); if ($resp === false) return ['ok' => false, 'error' => '无法连接认证中心: ' . $err, 'code' => 'network']; $arr = json_decode($resp, true); return is_array($arr) ? $arr : ['ok' => false, 'error' => '认证中心响应异常', 'code' => 'bad_response']; } /* ============ 业务封装 ============ */ /** 平台内注册(中心统一建档并绑定本平台) */ function uc_register($username, $password, $extra = []) { return uc_api('user.register', array_merge(['username' => $username, 'password' => $password], $extra)); } /** 账号密码登录校验(通过即绑定本平台) */ function uc_login($username, $password) { return uc_api('user.login', ['username' => $username, 'password' => $password]); } /** SSO 跳转地址 */ function uc_sso_url($back_url) { global $_UC_CFG; return $_UC_CFG['url'] . '/sso.php?app_id=' . urlencode($_UC_CFG['app_id']) . '&back=' . urlencode($back_url); } /** 回跳页处理:校验 GET 中的 ticket 并换取用户信息(一次性)。成功返回用户数组,失败返回 null */ function uc_handle_sso() { if (empty($_GET['ticket'])) return null; $r = uc_api('ticket.verify', ['ticket' => $_GET['ticket']]); if (!empty($r['ok'])) return $r; return null; } /** 本地校验回跳签名(不请求中心,验证 uid/ts/sign 三个参数) */ function uc_callback_verify() { global $_UC_CFG; $p = ['ticket' => $_GET['ticket'] ?? '', 'uid' => $_GET['uid'] ?? '', 'ts' => $_GET['ts'] ?? '', 'sign' => $_GET['sign'] ?? '']; if (!$p['ticket'] || !preg_match('/^\d{10}$/', $p['ts']) || abs(time() - (int)$p['ts']) > 300) return null; $expect = hash('sha256', $_UC_CFG['app_key'] . '|' . $p['ticket'] . '|' . $p['uid'] . '|' . $p['ts']); if (!hash_equals($expect, $p['sign'])) return null; return ['uid' => (int)$p['uid'], 'ticket' => $p['ticket']]; } /** 校验平台令牌(7 天有效),成功返回用户数组 */ function uc_check_token($token) { $r = uc_api('token.verify', ['token' => $token]); return !empty($r['ok']) ? $r : null; } /** 查询用户资料 */ function uc_user_info($uidOrUsername) { $field = is_numeric($uidOrUsername) ? 'uid' : 'username'; $r = uc_api('user.info', [$field => $uidOrUsername]); return !empty($r['ok']) ? $r['user'] : null; } /** 修改密码(全平台同步生效) */ function uc_change_password($username, $old, $new) { return uc_api('user.changepwd', ['username' => $username, 'old_password' => $old, 'new_password' => $new]); } /** 同步登出(销毁平台令牌) */ function uc_logout($token) { return uc_api('syn.logout', ['token' => $token]); } /** * 平台账号密码登录成功后调用:输出同步登录广播脚本, * 写入中心免登 Cookie,使其它接入平台 SSO 免密通行(对齐 Discuz UCenter synlogin)。 * 用法:登录成功后 echo uc_synlogin_script($uid); */ function uc_synlogin_script($uid) { global $_UC_CFG; $ts = time(); $sign = hash('sha256', $_UC_CFG['app_key'] . '|' . (int)$uid . '|' . $ts); return ''; } /** 检查与中心的连通与密钥正确性 */ function uc_ping() { return uc_api('app.ping'); }