如何在WordPress中安全存储和使用API Token?
2024-07-10 06:18:57
如何安全存储授权 Token 并连接外部 API?
在开发与外部 API 交互的网站时,安全地存储和管理授权 token 至关重要。本文将以 WordPress 环境为例,探讨如何安全存储从 Telco API 获取的 Bearer Token,并实现电话号码验证及用户级别折扣,整个过程无需借助任何插件。
场景分析
假设您正在构建一个需要验证用户手机号码的网站,而这个验证过程依赖于一家电信公司提供的外部 API。该公司根据用户级别("Silver", "Gold", "Platinum")提供不同的服务和折扣。
您面临的挑战是如何安全地存储每次 OAuth 验证后动态生成的 Bearer Token,以及如何在 WordPress 中不使用插件的情况下实现整个流程。
解决方案解析
安全存储 Bearer Token
Bearer Token 相当于访问受保护资源的密钥,直接将其存储在数据库或代码中会带来极大的安全风险。 为了保障您的网站和用户数据安全,我们可以采取以下两种更安全的存储方式:
- WordPress Transients API: Transients API 允许您将数据存储在数据库中,并设置过期时间。您可以使用它来存储 Bearer Token,并设置一个合理的过期时间,例如 API 设定的 token 有效期。
// 获取 token
$token = get_transient( 'telco_api_token' );
// 如果 token 不存在或已过期,则重新获取
if ( false === $token ) {
// ... 您的 OAuth 验证逻辑,获取新的 token ...
// 设置 token 过期时间,例如 1 小时
set_transient( 'telco_api_token', $token, HOUR_IN_SECONDS );
}
// 使用 token 进行 API 调用
// ...
- 服务器端 Session: 如果您的服务器支持 Session,您可以将 Bearer Token 存储在 Session 中。Session 数据存储在服务器端,安全性更高,并且会在用户关闭浏览器或 Session 过期后自动清除,无需担心数据残留。
session_start();
// 获取 token
$token = isset( $_SESSION['telco_api_token'] ) ? $_SESSION['telco_api_token'] : false;
// 如果 token 不存在,则重新获取
if ( !$token ) {
// ... 您的 OAuth 验证逻辑,获取新的 token ...
// 将 token 存储在 Session 中
$_SESSION['telco_api_token'] = $token;
}
// 使用 token 进行 API 调用
// ...
集成到 WordPress 流程
获取并安全存储 token 后,我们需要将其集成到 WordPress 的工作流程中,以实现电话号码验证和用户级别折扣。以下两个场景为您展示具体的实现方法:
- Forminator 表单验证: 借助 Forminator 表单的自定义代码功能,我们可以在用户提交表单时验证电话号码。
// 获取存储的 token
$token = get_transient( 'telco_api_token' );
// 发起 API 请求验证电话号码
$response = wp_remote_post( 'https://api.telco.com/v1/phone-verification', array(
'headers' => array(
'Authorization' => 'Bearer ' . $token,
),
'body' => array(
'phone_number' => $_POST['phone_number'],
),
) );
// 处理 API 响应
if ( is_wp_error( $response ) ) {
// 处理错误
} else {
$body = json_decode( wp_remote_retrieve_body( $response ) );
if ( $body->status === 'success' ) {
// 验证成功,根据用户级别应用折扣
switch ( $body->customer_status ) {
case 'gold':
$coupon_code = 'gold1';
break;
// ... 其他用户级别 ...
}
if ( $coupon_code && ! WC()->cart->has_discount( $coupon_code ) ) {
WC()->cart->apply_coupon( $coupon_code );
}
} else {
// 验证失败,显示错误信息
}
}
- 结账页面验证: 在 WooCommerce 的结账页面,我们也可以进行类似的操作。通过
woocommerce_checkout_process
钩子函数,我们可以在用户结账时验证电话号码并应用相应的折扣。
function verify_api_phonenumber() {
if ( isset( $_POST['billing_phone'] ) ) {
$phone_number = sanitize_text_field( $_POST['billing_phone'] );
// 获取存储的 token
$token = get_transient( 'telco_api_token' );
// 发起 API 请求验证电话号码
// ... (参考上面的代码示例) ...
}
}
add_action( 'woocommerce_checkout_process', 'verify_api_phonenumber' );
代码优化建议
为了提高代码的可读性和可维护性,以下代码优化建议供您参考:
function verify_api_phonenumber() {
// 检查电话号码字段是否存在
if ( ! isset( $_POST['billing_phone'] ) ) {
return;
}
$phone_number = sanitize_text_field( $_POST['billing_phone'] );
// 获取存储的 token
$token = get_transient( 'telco_api_token' );
// 如果 token 不存在或已过期,可以考虑重新获取或进行其他处理
if ( false === $token ) {
// ... 处理 token 获取失败的情况 ...
return;
}
// 发起 API 请求验证电话号码
$response = wp_remote_post( 'https://api.telco.com/v1/phone-verification', array(
'headers' => array(
'Authorization' => 'Bearer ' . $token,
),
'body' => array(
'phone_number' => $phone_number,
),
) );
// 处理 API 响应
if ( is_wp_error( $response ) ) {
// 处理 API 请求错误
// ...
return;
}
$body = json_decode( wp_remote_retrieve_body( $response ) );
// 检查 API 响应状态
if ( ! isset($body->status) || $body->status !== 'success' ) {
// 处理验证失败
// ...
return;
}
// 验证成功,应用折扣
apply_discount_based_on_customer_status( $body->customer_status );
}
add_action( 'woocommerce_checkout_process', 'verify_api_phonenumber' );
// 根据用户级别应用折扣
function apply_discount_based_on_customer_status( $customer_status ) {
$coupon_code = '';
switch ( $customer_status ) {
case 'gold':
$coupon_code = 'gold1';
break;
// ... 其他用户级别 ...
}
if ( $coupon_code && ! WC()->cart->has_discount( $coupon_code ) ) {
WC()->cart->apply_coupon( $coupon_code );
}
}
常见问题解答
1. 为什么不能直接将 Bearer Token 存储在数据库或代码中?
直接将 Bearer Token 存储在数据库或代码中会使其容易受到攻击者的攻击。如果攻击者获得了对您数据库或代码的访问权限,他们就可以窃取所有用户的 Bearer Token,从而冒充用户访问敏感信息。
2. Transients API 和 Session 哪个更适合存储 Bearer Token?
这取决于您的具体需求和服务器环境。如果您的服务器支持 Session,并且您希望在用户关闭浏览器后自动清除 Bearer Token,那么 Session 是一个不错的选择。 如果您需要更精细地控制过期时间,或者您的服务器不支持 Session,那么 Transients API 更为合适。
3. 如何设置 Transients API 的过期时间?
您可以使用 WordPress 函数 set_transient()
的第三个参数来设置过期时间,单位为秒。例如,要将过期时间设置为 1 小时,可以使用 HOUR_IN_SECONDS
常量。
4. 如何处理 Bearer Token 过期的情况?
您可以通过检查 Transients API 或 Session 中存储的 Bearer Token 是否存在且未过期来判断 token 是否有效。如果 token 已过期,您需要重新执行 OAuth 验证流程以获取新的 token。
5. 除了 Forminator,还有哪些表单插件可以使用类似的方法?
大多数 WordPress 表单插件都提供了自定义代码或钩子函数,允许您在表单提交时执行自定义逻辑。 您可以根据您使用的具体插件查阅相关文档,实现类似的电话号码验证和折扣应用功能。