WordPress 自定义 JWT 授权和验证
像素鱼丸
2024-05-04
680

WordPress 自带的 RESTful API 内置的身份验证方法是 Cookie Authentication ,登录仪表板时,会生成cookie。为了防止CSRF,需要在请求的地址后面,加上一个 nonce 参数“_wpnonce”。

CSRF请参考:https://javascript.net.cn/article?id=683

nonce生成,参考:https://verytheme.com/archives/136

如果想使用JWT(JSON Web Token),官方建议使用插件 https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/

但是这个插件只能使用用户名和密码登录,二次开发使用手机号或者验证码登录的话是不可以的,所以自己写了一个大概,可以完成注册、登录和验证。

一,WordPress JWT 用户注册接口

/* -------------------------------------------------------------------------- *
 * 用户注册接口 http://test.com/wp-json/verytheme/v1/register
 */
add_action('rest_api_init', 'register_route_hook');
function register_route_hook()
{
    register_rest_route('verytheme/v1', 'register', [
        'methods'  => 'POST',
        'callback' => 'register_callback'
    ]);
}


function register_callback($request)
{
    //获取注册页面提交时候的表单数据
    $redirect_to = sanitize_user($_REQUEST['redirect_to']) ? sanitize_user($_REQUEST['redirect_to']) : home_url();
    if (!empty($_POST['reg_flag'])) {
        $error = '';
        $sanitized_user_login       = sanitize_user($_POST['user_login']);
        $user_website               = sanitize_user($_POST['website']);
        $user_description           = sanitize_user($_POST['description']);
        $user_nickname              = sanitize_user($_POST['nickname']);
        $user_email                 = apply_filters('user_registration_email', $_POST['user_email']);


        // 验证邮箱
        if ($user_email == '') {
            // 一些代码 ...
        } 
        // 验证用户名
        if ($sanitized_user_login == '') {
            // 一些代码 ...
        }
        //验证密码
        if (strlen($_POST['user_pass']) < 6) {
            // 一些代码 ...
        }
        if ($error == '') {
            //验证全部通过进入注册信息添加
            $display_name = empty($user_nickname) ? $sanitized_user_login : $user_nickname;
            $user_pass = $_POST['user_pass'];
            $user_id = wp_insert_user(array(
                'user_login'    => $sanitized_user_login,
                'user_pass'     => $user_pass,
                'nickname'      => $user_nickname,
                'display_name'  => $display_name,
                'user_email'    => $user_email,
                'user_url'      => $user_website, 'description'   => $user_description
            ));
            //意外情况判断,添加失败
            if (!$user_id) {
                // 一些代码 ...
            }
        }
    }
}

二,WordPress JWT 登录接口

/* -------------------------------------------------------------------------- *
 * JWT 登录 http://test.com/wp-json/verytheme/v1/login
 */
add_action('rest_api_init', 'login_route_hook');
function login_route_hook()
{
    register_rest_route('verytheme/v1', 'login', [
        'methods'  => 'POST',
        'callback' => 'login_callback'
    ]);
}


function login_callback($request)
{
    $json = $request->get_json_params();
    $username = $json['username'];
    $password = $json['password'];


    global $wpdb;
    $user = $wpdb->get_results($wpdb->prepare("SELECT * FROM wp_users WHERE user_login=%s",$username));
    if(!$user){
        return new WP_Error(
            'jwt_auth_bad_request',
            '用户名或者密码错误',
            array(
                'status' => 403
            )
        );
    }


    if(!wp_check_password($password, $user[0]->user_pass)){
        return new WP_Error(
            'jwt_auth_bad_request',
            '用户名或者密码错误',
            array(
                'status' => 403
            )
        );
    }


    $res['token'] = createToken(1);
    $res['user']  = $user[0];


    return $res;
}



require_once get_template_directory() . "/extends/php-jwt/src/JWT.php";
require_once get_template_directory() . "/extends/php-jwt/src/BeforeValidException.php";
require_once get_template_directory() . "/extends/php-jwt/src/ExpiredException.php";
require_once get_template_directory() . "/extends/php-jwt/src/SignatureInvalidException.php";

三,WordPress JWT 生成JWT Token

/**
 * 生成JWT Token
 */
function createToken($user_id)
{
    $time                    = time();
    $payload['iat']          = $time;        // 签发时间
    $payload['exp']          = $time + 60*1000;   // 过期时间
    $payload['nbf']          = $time;        // 生效时间
    $payload['user_id']      = $user_id;  // 用户 ID
    $key    = defined('JWT_KEY') ? JWT_KEY : 'default_key';
    $token  = Firebase\JWT\JWT::encode($payload, $key);
    return $token;
}

四,验证JWT

默认情况下,筛选器使用此选项从请求的cookie(如果可用)中确定当前用户。所有的验证方法钩子都会调用determine_current_user过滤器,包括wp_validate_auth_cookie()。在生成JWT的时候,我们把user_id放入了JWT的Payload中,现在也可以在determine_current_user取出来,像中间价一样。

add_filter('determine_current_user', 'determine_current_user_callback' );
function determine_current_user_callback($user){

    $auth = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : false;


    list($token) = sscanf($auth, 'Bearer %s');
    if (!$token) {
        // echo "fuck";
        return 0;
    }


    $key    = defined('JWT_KEY') ? JWT_KEY : 'default_key';


    try {
        $data = Firebase\JWT\JWT::decode($token, $key, array('HS256'));
    } catch(Exception $e) {
        // echo 'Message: ' .$e->getMessage();
        return 0;
    }


    return $data->user_id ? $data->user_id : 0;
}
收藏
打赏
WordPress 常用的路径
上一篇
WP_Query 函数
下一篇

发表评论

注册不是必须的

像素鱼丸
160 文章
2 评论
4 喜欢
最新文章

VooShop 商城主题

主题简介 Vooshop 是一个简单精美的 WordPress 主题,支持自适应、暗黑模式、多语言等功能,可以用于企业、团体、自由职业者或更广泛的主页。 Vooshop:回归 WooCommerce 的纯粹与极速 零冗余代码,零多余功能。一个完全依赖 WooCommerce 原生能力的轻量级主题。 Vooshop 不做 WooCommerce 做不到的事,我们只负责让它跑得更快。 市面上的主题总试 […]

XZhan 主题

主题简介 XZhan 主题(中文名称:小站主题)是一款 WordPress 企业主题,支持自适应、暗黑模式等功能,可快速构建高质量的企业网站。   主题特色 支持白天与暗黑模式 自适应设计,兼容多种主流浏览器 自定义主色调 LOGO扫光动画 自定义SMTP支持 内置SEO功能 文章支持点赞、分享和海报生成 丰富的小工具 侧边栏粘性滚动 简介的主题设置面板 主题设置可导入和备份 多级子菜单 […]

StarFish 配置框架

一个轻量级的 WordPress 选项框架插件,通过配置化的方式,快速为 WordPress 主题或插件生成后台设置页面。 ✨ 特性 🎯 配置驱动 UI:只需定义数组配置,自动生成完整的表单界面 📱 多页面架构:支持多个独立的设置页面 🎨 丰富的字段类型:包含 15+ 种常用字段类型 🔗 字段依赖系统:实现字段间的联动效果 ✅ 数据验证与清理:自动进行安全清理,防止 XSS 攻击 🚀 零依赖:使用 […]

什么是幽灵按钮

“幽灵按钮”(Ghost Button)是一种常见的网页与移动应用 UI 设计模式,指背景透明(或半透明)、仅通过边框(border)和文字(text)定义的按钮,视觉上“若隐若现”,仿佛“幽灵”一般——因此得名。 核心特征: 无填充色(transparent background) 背景完全透明(或与父容器同色),不遮挡背后内容。 清晰的边框(通常 1–2px 实线) 如 border: 2px […]
生成中...
扫描二维码
扫描二维码
确认购买

您确定要购买此资源吗?

微信扫码支付

请使用微信扫描二维码完成支付

订单号:

等待支付...