<?php if (!defined('ABSPATH')) { exit; } final class Zibll_Oauth_Netease { const OPTIONS_KEY = 'zibll_oauth_netease_options'; const PROVIDER_TYPE = 'netease'; public static function init() { add_action('template_redirect', array(__CLASS__, 'handle_oauth_callback')); add_filter('zib_oauth_login_url', array(__CLASS__, 'add_oauth_login_url'), 10, 2); add_action('wp_footer', array(__CLASS__, 'enqueue_frontend_assets')); add_filter('zib_social_type_data', array(__CLASS__, 'add_social_type_data')); add_filter('user_center_account_setup', array(__CLASS__, 'add_oauth_set'), 100, 2); add_action('wp_ajax_user_oauth_untying', array(__CLASS__, 'handle_oauth_untying'), 5); add_action('wp_ajax_nopriv_user_oauth_untying', array(__CLASS__, 'handle_oauth_untying'), 5); add_filter('query_vars', array(__CLASS__, 'add_query_vars')); register_activation_hook(ZIBLL_OAUTH_PLUGIN_FILE, array(__CLASS__, 'activate')); } public static function add_query_vars($vars) { $vars[] = 'oauth'; $vars[] = 'oauth_callback'; return $vars; } public static function activate() { add_rewrite_rule('^oauth/netease/callback/?$', 'index.php?oauth=netease&oauth_callback=1', 'top'); flush_rewrite_rules(); } public static function get_options() { $cache_key = 'options:' . self::OPTIONS_KEY; $cached = wp_cache_get($cache_key, Zibll_Oauth_Options::CACHE_GROUP); if (is_array($cached)) { return $cached; } $opt = get_option(self::OPTIONS_KEY, array( 'netease_enabled' => true, 'netease_client_id' => '', 'netease_client_secret' => '', 'netease_logo_url' => '', 'netease_login_text' => '网易通行证' )); $opt = is_array($opt) ? $opt : array(); wp_cache_set($cache_key, $opt, Zibll_Oauth_Options::CACHE_GROUP, 300); return $opt; } public static function get($key, $default = '') { $opt = self::get_options(); return array_key_exists($key, $opt) ? $opt[$key] : $default; } public static function get_netease_config() { return array( 'client_id' => sanitize_text_field(self::get('netease_client_id', '')), 'client_secret' => sanitize_text_field(self::get('netease_client_secret', '')), ); } public static function get_netease_redirect_uri() { return rtrim(home_url('/oauth/netease/callback'), '/'); } public static function get_authorize_url($state = '') { $config = self::get_netease_config(); if (empty($config['client_id'])) { return ''; } $params = array( 'client_id' => $config['client_id'], 'redirect_uri' => self::get_netease_redirect_uri(), 'response_type' => 'code', 'state' => $state ); return 'https://reg.163.com/open/oauth2/authorize.do?' . http_build_query($params); } public static function handle_oauth_callback() { $oauth = get_query_var('oauth'); $oauth_callback = get_query_var('oauth_callback'); if ($oauth !== 'netease' || !$oauth_callback) { return; } if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'init', '接收到网易通行证回调请求'); } $options = self::get_options(); if (empty($options['netease_enabled'])) { if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'error', '网易通行证登录功能已被禁用'); } zib_oauth_die('功能未启用', '网易通行证登录功能已被禁用'); exit; } if (!isset($_GET['code'])) { if (isset($_GET['error'])) { $error_msg = isset($_GET['error_description']) ? $_GET['error_description'] : '未知错误'; if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'error', 'OAuth错误: ' . $error_msg); } zib_oauth_die('登录失败', $error_msg); exit; } if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'error', '缺少code参数'); } return; } if (!isset($_GET['state']) || !wp_verify_nonce($_GET['state'], 'netease_auth')) { if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'error', '安全验证失败'); } zib_oauth_die('验证失败', '安全验证失败'); exit; } $code = sanitize_text_field($_GET['code']); $config = self::get_netease_config(); if (empty($config['client_id']) || empty($config['client_secret'])) { if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'error', '网易通行证应用配置不完整'); } zib_oauth_die('配置错误', '网易通行证应用配置不完整'); exit; } if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'init', '开始获取access_token'); } try { $token_response = self::get_access_token($code); if (!isset($token_response['access_token']) || !is_string($token_response['access_token']) || empty($token_response['access_token'])) { $error_msg = isset($token_response['error']) ? $token_response['error'] : '获取访问令牌失败'; if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'error', '获取token失败: ' . $error_msg); } zib_oauth_die('网易通行证登录错误', $error_msg); exit; } $access_token = sanitize_text_field($token_response['access_token']); $user_data = self::get_user_info($access_token); if (!isset($user_data['userId']) || !is_string($user_data['userId']) || empty($user_data['userId'])) { if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'error', '无法获取用户信息'); } zib_oauth_die('获取用户信息失败', '无法获取用户信息'); exit; } $open_id = sanitize_text_field($user_data['userId']); $name = isset($user_data['username']) ? sanitize_text_field($user_data['username']) : '网易用户'; $avatar = ''; if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'init', '成功获取用户信息: ' . $name); } if (isset($_GET['bind'])) { if (!is_user_logged_in()) { if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'bind', 'error', '绑定操作需要先登录'); } zib_oauth_die('绑定失败', '请先登录后再绑定账号'); exit; } if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'bind', 'init', '开始绑定账号'); } $args = array( 'meta_key' => 'oauth_netease_openid', 'meta_value' => $open_id, 'number' => 1, 'count_total' => false ); $existing_users = get_users($args); if (!empty($existing_users)) { if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'bind', 'error', '该账号已被其他用户绑定'); } zib_oauth_die('绑定失败', '该账号已被其他用户绑定'); exit; } } $user_args = array( 'type' => 'netease', 'openid' => $open_id, 'name' => $name, 'avatar' => $avatar, 'description' => '', 'getUserInfo' => $user_data, ); if (function_exists('zib_oauth_update_user')) { $action = isset($_GET['bind']) ? '绑定' : '登录'; if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', $action, 'success', '用户: ' . $name . ' ' . $action . '成功'); } zib_oauth_update_user($user_args); wp_redirect(home_url()); exit; } } catch (Exception $e) { if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'callback', 'error', '错误: ' . $e->getMessage()); } zib_oauth_die('网易通行证登录错误', '登录过程中发生错误,请稍后重试'); exit; } } public static function get_access_token($code) { $config = self::get_netease_config(); $params = array( 'grant_type' => 'authorization_code', 'client_id' => $config['client_id'], 'client_secret' => $config['client_secret'], 'code' => $code, 'redirect_uri' => self::get_netease_redirect_uri() ); $response = wp_remote_post('https://reg.163.com/open/oauth2/token.do', array( 'timeout' => 30, 'sslverify' => true, 'body' => $params, 'headers' => array( 'Content-Type' => 'application/x-www-form-urlencoded' ) )); if (is_wp_error($response)) { throw new Exception('连接网易通行证服务器失败: ' . $response->get_error_message()); } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception('响应数据解析失败'); } return $data; } public static function get_user_info($access_token) { $response = wp_remote_get('https://reg.163.com/open/oauth2/getUserInfo.do', array( 'timeout' => 30, 'sslverify' => true, 'headers' => array( 'Accept' => 'application/json', 'Authorization' => 'Bearer ' . $access_token ) )); if (is_wp_error($response)) { throw new Exception('获取用户信息失败: ' . $response->get_error_message()); } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception('用户信息数据解析失败'); } return $data; } public static function add_oauth_login_url($url, $type) { if ($type !== self::PROVIDER_TYPE) { return $url; } return self::get_authorize_url(wp_create_nonce('netease_auth')); } public static function add_social_type_data($data) { $options = self::get_options(); if (!empty($options['netease_client_id']) && !empty($options['netease_client_secret'])) { $data[] = array( 'type' => self::PROVIDER_TYPE, 'name' => $options['netease_login_text'] ?: '网易通行证', 'icon' => 'custom-netease-icon' ); } return $data; } public static function add_oauth_set($html, $user_id) { if (!$user_id) { return $html; } $options = self::get_options(); if (empty($options['netease_enabled']) || empty($options['netease_client_id']) || empty($options['netease_client_secret'])) { return $html; } $rurl = zib_get_user_center_url('account'); $bind_href = zib_get_oauth_login_url('netease', $rurl); if (!$bind_href) { return $html; } $oauth_info = zib_get_user_meta($user_id, 'oauth_netease_getUserInfo', true); $oauth_id = get_user_meta($user_id, 'oauth_netease_openid', true); if ($oauth_info && $oauth_id) { $user_name = !empty($oauth_info['username']) ? esc_attr($oauth_info['username']) : '网易通行证账号'; $user_avatar = ''; $avatar_html = ''; if ($user_avatar) { $lazy_attr = zib_get_lazy_attr('lazy_avatar', $user_avatar, 'avatar', ZIB_TEMPLATE_DIRECTORY_URI . '/img/thumbnail-null.svg'); $avatar_html = '<span class="avatar-img avatar-sm mr6" style="--this-size: 22px;"><img ' . $lazy_attr . ' alt="网易通行证头像' . zib_get_delimiter_blog_name() . '"></span>'; } $desc = $avatar_html ? $avatar_html . $user_name : '已绑定"' . $user_name . '"'; $desc = '<div class="muted-2-color text-ellipsis mr10 ml20" data-toggle="tooltip" title="已绑定网易通行证账号">' . $desc . '</div>'; $btn = '<a data-toggle="tooltip" href="javascript:;" openid="' . esc_attr($oauth_id) . '" title="解绑网易通行证账号" user-id="' . esc_attr($user_id) . '" untying-type="netease" class="em09 p2-10 oauth-untying but hollow c-yellow">解绑</a>'; } else { $desc = '<div class="muted-2-color">暂未绑定</div>'; $btn = '<a title="绑定网易通行证账号" href="' . esc_url(add_query_arg(array('bind' => 'netease'), $bind_href)) . '" class="em09 p2-10 but hollow c-blue">绑定</a>'; } $parts = array( '<div class="mb10"><div class="flex ac jsb muted-box">', '<div class="flex ac type-logo"><span class="social-login-item circular mr6 em12 netease"><i class="custom-netease-icon" aria-hidden="true"></i></span><span class="">' . esc_html($options['netease_login_text'] ?: '网易通行证') . '</span></div>', '<div class="overflow-hidden">' . $desc . '</div>', '<div class="shrink0">' . $btn . '</div>', '</div></div>' ); $pos = strpos($html, 'class="box-body oauth-set"'); if ($pos !== false) { $pos = strpos($html, 'class="flex hh oauth-bind-box gutters-5"', $pos); if ($pos !== false) { $pos = strpos($html, '>', $pos) + 1; $html = substr($html, 0, $pos) . implode('', $parts) . substr($html, $pos); } } return $html; } public static function handle_oauth_untying() { if (empty($_POST['user_id']) || empty($_POST['type'])) { return; } $type = $_POST['type']; if ($type !== self::PROVIDER_TYPE) { return; } if (empty($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'netease_untying')) { wp_send_json_error(array('msg' => '安全验证失败', 'ys' => 'danger')); exit; } $user_id = (int)$_POST['user_id']; $current_user_id = get_current_user_id(); if (!$current_user_id || $current_user_id != $user_id) { wp_send_json_error(array('msg' => '权限不足', 'ys' => 'danger')); exit; } delete_user_meta($user_id, 'oauth_netease_openid'); zib_update_user_meta($user_id, 'oauth_netease_getUserInfo', false); if (class_exists('Zibll_Oauth_TikTok')) { Zibll_Oauth_TikTok::add_auth_log('netease', 'unbind', 'success', '用户ID: ' . $user_id . ' 解除绑定成功'); } $goto = zib_get_user_center_url('account'); wp_send_json(array( 'error' => 0, 'msg' => '已解除绑定', 'ys' => 'success', 'reload' => true, 'goto' => $goto )); exit; } public static function enqueue_frontend_assets() { $options = self::get_options(); if (empty($options['netease_enabled']) || empty($options['netease_client_id']) || empty($options['netease_client_secret'])) { return; } $auth_url = self::get_authorize_url(wp_create_nonce('netease_auth')); $logo_url = $options['netease_logo_url']; $login_text = $options['netease_login_text'] ?: '网易通行证'; ?> <style> .social-login-item.netease { background: <?php echo $logo_url ? '#000 url(' . esc_url($logo_url) . ') no-repeat center/cover' : '#cc0000'; ?> !important; color: #fff !important; position: relative; width: 32px !important; height: 32px !important; line-height: 32px !important; text-align: center; border-radius: 50px; margin: 3px 5px; display: inline-flex !important; align-items: center; justify-content: center; font-size: 16px; vertical-align: middle; } .social-login-item.netease:hover { opacity: .8; color: #fff !important; text-decoration: none; } .social-login-item.netease.button-lg { width: 120px !important; font-size: 14px; justify-content: center; } .social-login-item.netease.button-lg .custom-netease-icon { margin-right: 6px; } .custom-netease-icon { display: inline-block; width: 14px; height: 14px; vertical-align: middle; position: relative; top: 0; background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOHMzLjU5LTggOC04IDggMy41OSA4IDgtMy41OSA4LTggOHptLTItOWg0djJoLTR6bTAtM2g0djJoLTR6Ii8+PC9zdmc+'); background-repeat: no-repeat; background-position: center; background-size: contain; } .oauth-bind-box .social-login-item.netease { margin: 0 !important; width: 35.28px !important; height: 35.28px !important; line-height: 35.28px !important; font-size: 16px !important; display: inline-flex !important; align-items: center; justify-content: center; } .oauth-bind-box .custom-netease-icon { width: 22px !important; height: 22px !important; top: 0 !important; } </style> <script> jQuery(document).ready(function($) { var neteaseButtonClass = '<?php echo _pz('oauth_button_lg') ? 'button-lg' : 'toggle-radius'; ?>'; var neteaseButtonText = neteaseButtonClass === 'button-lg' ? '<?php echo esc_js($login_text); ?>' : ''; var neteaseButton = '<a rel="nofollow" title="<?php echo esc_js($login_text); ?>" href="<?php echo esc_url($auth_url); ?>" class="social-login-item netease ' + neteaseButtonClass + '"><i class="custom-netease-icon" aria-hidden="true"></i>' + neteaseButtonText + '</a>'; function insertNeteaseButton() { $('.social_loginbar').each(function() { var $container = $(this); if ($container.find('.social-login-item.netease').length === 0) { $container.append(neteaseButton); } }); } insertNeteaseButton(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.addedNodes.length) { mutation.addedNodes.forEach(function(node) { if (node.nodeType === 1 && ( $(node).hasClass('social_loginbar') || $(node).find('.social_loginbar').length )) { insertNeteaseButton(); } }); } }); }); observer.observe(document.body, { childList: true, subtree: true }); $(document).on('click', '.oauth-untying[untying-type="netease"]', function() { var _this = $(this); var user_id = _this.attr('user-id'); var openid = _this.attr('openid'); var type = _this.attr('untying-type'); if (!user_id || !openid) return; $.confirm({ title: '确认解除绑定?', text: '解绑后将无法使用网易通行证账号登录', type: 'red', confirmButton: '确认解绑', cancelButton: '取消', onConfirm: function() { zib_ajax(_this, 'user_oauth_untying', { user_id: user_id, type: type, openid: openid, nonce: '
Fatal error: Uncaught Error: Call to undefined function wp_create_nonce() in /www/wwwroot/zyzhixi.com/wp-content/plugins/zibll-oauth/includes/admin-netease.php:541 Stack trace: #0 /www/wwwroot/zyzhixi.com/wp-content/plugins/zibll-oauth/zibll-oauth.php(37): require_once() #1 /www/wwwroot/zyzhixi.com/wp-settings.php(560): include_once('...') #2 /www/wwwroot/zyzhixi.com/wp-config.php(102): require_once('...') #3 /www/wwwroot/zyzhixi.com/wp-load.php(50): require_once('...') #4 /www/wwwroot/zyzhixi.com/wp-blog-header.php(13): require_once('...') #5 /www/wwwroot/zyzhixi.com/index.php(17): require('...') #6 {main} thrown in /www/wwwroot/zyzhixi.com/wp-content/plugins/zibll-oauth/includes/admin-netease.php on line 541