特级教程:如何利用wp的Nonce或者password application来实现插件rest api发送的验证功能(PHP-AJAX版)
2023-02-19
浏览次数 : 172
这两天我遇到了一个十分不解的事情,我编写插件的时候,需要设置接口的访问权限,防止滥用,因为是post提交,如果滥用对数据也会产生极大的风险。
我第一个想到的是用nonce.
我先在插件里通过wp_localize_script创建nonce,
将这个放置在wp_enqueue_script的最后,
wp_localize_script( 'plugin_index', 'ha_submission',array(
'site_url' => home_url(),
'nonce' => wp_create_nonce('plugin_ha_submission')
) );
然后我在发送ajax的时候,设置beforeSend来添加发送时候的headers里面的X-WP-Nonce.
$.ajax({
url:ha_submission.site_url + '/wp-json/ha_submission/v1/submission',
beforeSend: function(xhr) {
xhr.setRequestHeader('X-WP-Nonce',ha_submission.nonce)
},
method:'POST',
data:$(this).serialize(),
success: res => { }
当然我事先是先添加了自定义的路由了的,并且路由访问都正常的。
然而问题来了,这个beforeSend里面的nonce怎样都不能用, 永远返回的是cookie_invalid_nonce 错误,返回403。
足足折腾了两天。
重磅更新
用nonce可以通过authentication,但是这个nonce的action必须是wp_rest, 也就是说,在本地化wp_localize_script里面,nonce必须设置 nonce=>wp_create_nonce(‘wp_rest)
官方网址:https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/
利用nonce写法
<?php
wp_localize_script( 'wp-api', 'wpApiSettings', array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' )
) );
options.beforeSend = function(xhr) {
xhr.setRequestHeader('X-WP-Nonce', wpApiSettings.nonce);
if (beforeSend) {
return beforeSend.apply(this, arguments);
}
};
$.ajax( {
url: wpApiSettings.root + 'wp/v2/posts/1',
method: 'POST',
beforeSend: function ( xhr ) {
xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce );
},
data:{
'title' : 'Hello Moon'
}
} ).done( function ( response ) {
console.log( response );
} );
然后我突然想用wp两年前刚出的application password功能。
问题一下子迎刃而解。
首先定义用户名和密码,用户名是你网站管理员用户名,密码是你在后台用户那里生成的application password.
const username = '';
const password = '';
然后通过base64 基本验证来进行加密: 也是使用必须的要求:
const credentials = `${username}:${password}`;
const encodedCredentials = btoa(credentials);
然后在ajax发送数据传递参数那里,设置headers
headers: {
'Authorization': `Basic ${encodedCredentials}`
},
完整代码如下:用户名和密码需要修改你自己的 (注意这里btoa用法) beforeSend用法 我还没测试过:
const username = '';
const password = '';
const credentials = `${username}:${password}`;
const encodedCredentials = btoa(credentials);
$("#submission_form").on('submit',function(e) {
e.preventDefault();
//form validation
if ($(this)[0].checkValidity() && $("#verify").val() == 6547) {
console.log(ha_submission.nonce);
$.ajax({
url:ha_submission.site_url + '/wp-json/ha_submission/v1/submission',
headers: {
'Authorization': `Basic ${encodedCredentials}`
},
method:'POST',
data:$(this).serialize(),
success: res => {
console.log(res);
$(this)[0].reset();
$("#formAlert").html("<h2 style='color:green'>成功提交信息,页面即将跳转</h2>");
setTimeout(function (argument) {
// body...
$("#formAlert").html('');
window.location = ha_submission.site_url;
},1500);
console.log('success');
},
error: err => {
$("#formAlert").html("<h2 style='color:red'>内部服务器错误</h2>")
console.log(err.responseText);
console.log('Fail in xmdn');
}
})
} else {
$("#verifyAlert").html("<p style='color:red'>答案不正确请重新输入</p>");
setTimeout(function(){$("#verifyAlert").html('')},1500);
console.log('请检查表单输入!');
}
});
BINGGO。比用nonce好用多了。 这样别人就无法通过这个接口来实现post提交了。因为实现Post提交的接口已经被我拦截了。至于Nonce 为什么不能用。我还在研究。照理说代码已经完美了。
当然最后也可以在接口php那里post提交那里进行后端验证,比方说验证是否是本网站发出的 不然可以拦截请求。
后端验证的方法实现必须要这个加密才能访问这个POST接口,一切都完美了
<?php
if (!isset($_SERVER['HTTP_AUTHORIZATION']) || empty($_SERVER['HTTP_AUTHORIZATION'])) {
// Authorization header is not set or is empty, handle the error
header('HTTP/1.1 401 Unauthorized');
echo 'Authorization header is missing or empty';
exit;
}
// Authorization header is set, decode the credentials
$auth_header = $_SERVER['HTTP_AUTHORIZATION'];
list($auth_type, $auth_data) = explode(' ', $auth_header, 2);
if ($auth_type !== 'Basic') {
// Unsupported authorization type, handle the error
header('HTTP/1.1 401 Unauthorized');
echo 'Unsupported authorization type';
exit;
}
$auth_data = base64_decode($auth_data);
list($username, $password) = explode(':', $auth_data, 2);
// Now you can use the $username and $password to authenticate the user
// and perform the necessary actions with the WordPress REST API
?>
检测nonce是这样的:
if (!isset($_POST[‘subscriber_nonce’]) && !wp_verify_nonce(‘subscriber_nonce’,basename(FILE))) {
return $post_id;
}
用beforeSend验证“:
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", `Basic ${encodedCredentials}`);
},