<?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