WordPress自定义插件实现OAuth2:实施思路与路由规划问询
WordPress 自定义 OAuth2 授权服务器实现方案
所需核心路由数量
根据OAuth2规范及你的需求,至少需要3个核心路由,对应授权服务器的标准端点:
- 授权端点(Authorization Endpoint):处理用户授权请求,生成授权码
- 令牌端点(Token Endpoint):用授权码/客户端凭证等换取访问令牌、刷新令牌
- 用户信息端点(User Info Endpoint):通过有效访问令牌获取用户信息
如果需要支持客户端动态注册,可额外添加1个客户端注册路由,但自用场景下通常硬编码客户端信息即可,无需额外路由。
具体实施思路
1. 插件基础搭建与依赖引入
- 创建自定义插件目录,通过Composer安装
thephpleague/oauth2-server库,在插件主文件中引入Composer的autoload.php - 定义插件激活/停用钩子,确保依赖加载正常
2. 配置OAuth2服务器核心组件
需要实现以下核心存储类(对接WordPress数据库):
- 客户端存储:存储客户端ID、密钥、重定向URI等信息(可自定义表或用选项存储)
- 授权码存储:临时存储授权码,用于换取令牌
- 令牌存储:存储访问令牌、刷新令牌及关联的用户ID
- 用户认证提供者:对接WordPress的
wp_authenticate函数,验证用户名密码的有效性
示例核心初始化代码:
use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Grant\AuthorizationCodeGrant; use YourPlugin\Repositories\ClientRepository; use YourPlugin\Repositories\AuthCodeRepository; use YourPlugin\Repositories\AccessTokenRepository; use YourPlugin\Repositories\RefreshTokenRepository; use YourPlugin\Repositories\UserRepository; function init_oauth_server() { $clientRepo = new ClientRepository(); $authCodeRepo = new AuthCodeRepository(); $accessTokenRepo = new AccessTokenRepository(); $refreshTokenRepo = new RefreshTokenRepository(); $userRepo = new UserRepository(); // 加密密钥(从WordPress配置或插件选项获取) $privateKey = file_get_contents(plugin_dir_path(__FILE__) . 'private.key'); $encryptionKey = 'your-encryption-key-here'; $server = new AuthorizationServer( $clientRepo, $accessTokenRepo, $authCodeRepo, $privateKey, $encryptionKey ); // 添加授权码授权模式(符合你的登录场景) $grant = new AuthorizationCodeGrant( $authCodeRepo, $refreshTokenRepo, new \DateInterval('PT10M') // 授权码有效期10分钟 ); $grant->setRefreshTokenTTL(new \DateInterval('P1M')); // 刷新令牌有效期1个月 $server->enableGrantType($grant, new \DateInterval('PT1H')); // 访问令牌有效期1小时 return $server; }
3. 实现各核心路由
授权端点路由
处理用户授权请求,未登录用户需跳转到WordPress登录页,登录后可添加授权确认逻辑:
register_rest_route('oauth2/v1', '/authorize', [ 'methods' => ['GET', 'POST'], 'callback' => 'handle_oauth_authorize', 'permission_callback' => '__return_true', // 允许未登录用户访问,后续内部验证 ]); function handle_oauth_authorize(WP_REST_Request $request) { $server = init_oauth_server(); $oauthRequest = \League\OAuth2\Server\RequestTypes\AuthorizationRequest::createFromGlobals(); // 检查用户是否登录 if (!is_user_logged_in()) { wp_redirect(wp_login_url(add_query_arg($_GET, rest_url('oauth2/v1/authorize')))); exit; } // 设置当前登录用户ID到授权请求 $userEntity = new class(get_current_user_id()) implements \League\OAuth2\Server\Entities\UserEntityInterface { protected $identifier; public function __construct($id) { $this->identifier = $id; } public function getIdentifier() { return $this->identifier; } }; $oauthRequest->setUser($userEntity); // 处理授权请求 try { $response = $server->validateAuthorizationRequest($oauthRequest); // 此处可添加授权确认页面逻辑,比如让用户手动确认是否授权 $response->setAuthorizationApproved(true); // 直接批准(或根据用户选择动态设置) $serverResponse = $server->completeAuthorizationRequest($response, new \Zend\Diactoros\Response()); } catch (\Exception $e) { return new WP_REST_Response(['error' => $e->getMessage()], 400); } // 重定向到客户端重定向URI wp_redirect($serverResponse->getHeaderLine('Location')); exit; }
令牌端点路由
处理授权码换取令牌的请求,同时支持刷新令牌逻辑:
register_rest_route('oauth2/v1', '/token', [ 'methods' => 'POST', 'callback' => 'handle_oauth_token', 'permission_callback' => '__return_true', // 客户端直接调用,无需WP登录 ]); function handle_oauth_token(WP_REST_Request $request) { $server = init_oauth_server(); $oauthRequest = \Zend\Diactoros\ServerRequestFactory::fromGlobals(); try { $response = $server->respondToAccessTokenRequest($oauthRequest, new \Zend\Diactoros\Response()); return new WP_REST_Response(json_decode((string)$response->getBody(), true), $response->getStatusCode()); } catch (\Exception $e) { return new WP_REST_Response(['error' => $e->getMessage()], 400); } }
用户信息端点路由
通过有效访问令牌获取自定义的用户信息字段:
register_rest_route('oauth2/v1', '/userinfo', [ 'methods' => 'GET', 'callback' => 'handle_oauth_userinfo', 'permission_callback' => 'validate_oauth_token', ]); function validate_oauth_token() { $server = init_oauth_server(); $oauthRequest = \Zend\Diactoros\ServerRequestFactory::fromGlobals(); try { $server->validateAuthenticatedRequest($oauthRequest); return true; } catch (\Exception $e) { return false; } } function handle_oauth_userinfo(WP_REST_Request $request) { // 获取令牌关联的用户ID(需在AccessTokenRepository中实现查询方法) $token = str_replace('Bearer ', '', $request->get_header('Authorization')); $userId = get_user_id_from_access_token($token); $user = get_user_by('id', $userId); // 返回自定义字段,可根据需求自由扩展 return new WP_REST_Response([ 'id' => $user->ID, 'username' => $user->user_login, 'email' => $user->user_email, 'display_name' => $user->display_name, // 添加你需要的自定义字段,比如用户角色、头像URL等 ], 200); }
4. 数据库表扩展
需要创建自定义表存储授权码、令牌、客户端信息,可在插件激活时执行SQL:
register_activation_hook(__FILE__, 'oauth2_plugin_activate'); function oauth2_plugin_activate() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); // 创建客户端表 $clients_table = $wpdb->prefix . 'oauth2_clients'; $sql = "CREATE TABLE $clients_table ( id bigint(20) NOT NULL AUTO_INCREMENT, client_id varchar(255) NOT NULL, client_secret varchar(255) NOT NULL, redirect_uri text NOT NULL, grant_types varchar(255) DEFAULT 'authorization_code', PRIMARY KEY (id), UNIQUE KEY client_id (client_id) ) $charset_collate;"; // 授权码表、令牌表的创建SQL类似,此处省略 require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); // 插入测试客户端(可后续通过插件设置页面管理) $wpdb->insert($clients_table, [ 'client_id' => 'test-client', 'client_secret' => 'test-secret', 'redirect_uri' => 'https://your-client-app.com/callback' ]); }
5. 测试与调试
- 用Postman等工具测试各端点:
- 访问授权端点获取授权码
- 用授权码调用令牌端点获取访问令牌
- 用访问令牌调用用户信息端点获取自定义字段
- 开启WordPress调试模式,排查路由或OAuth2库的错误
内容的提问来源于stack exchange,提问作者newbiedev
相关产品推荐
相关产品推荐

