OAuth 2.0 Server PHP实现示例
需求
实现三方OAuth2.0授权登录
使用OAuth服务
OAuth 2.0 Server PHP
环境
nginx
mysql
php
框架
Yii
一 安装
项目目录下安装应用
composer.phar require bshaffer/oauth2-server-php "^1.10"
二 构建数据结构
注意 user表需要自定义
CREATE TABLE oauth_clients ( client_id VARCHAR(80) NOT NULL, client_secret VARCHAR(80), redirect_uri VARCHAR(2000), grant_types VARCHAR(80), scope VARCHAR(4000), user_id VARCHAR(80), PRIMARY KEY (client_id) ); CREATE TABLE oauth_access_tokens ( access_token VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(80), expires TIMESTAMP NOT NULL, scope VARCHAR(4000), PRIMARY KEY (access_token) ); CREATE TABLE oauth_authorization_codes ( authorization_code VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(80), redirect_uri VARCHAR(2000), expires TIMESTAMP NOT NULL, scope VARCHAR(4000), id_token VARCHAR(1000), PRIMARY KEY (authorization_code) ); CREATE TABLE oauth_refresh_tokens ( refresh_token VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(80), expires TIMESTAMP NOT NULL, scope VARCHAR(4000), PRIMARY KEY (refresh_token) ); CREATE TABLE oauth_users ( username VARCHAR(80), password VARCHAR(80), first_name VARCHAR(80), last_name VARCHAR(80), email VARCHAR(80), email_verified BOOLEAN, scope VARCHAR(4000), PRIMARY KEY (username) ); CREATE TABLE oauth_scopes ( scope VARCHAR(80) NOT NULL, is_default BOOLEAN, PRIMARY KEY (scope) ); CREATE TABLE oauth_jwt ( client_id VARCHAR(80) NOT NULL, subject VARCHAR(80), public_key VARCHAR(2000) NOT NULL );
三 代码实现
<?php /** * Created by PhpStorm. * User: parker * Date: 2020/9/8 * Time: 7:08 下午 * * 使用 OAuth 2.0 Server PHP 搭建三方授权服务 * 相关文档地址 https://bshaffer.github.io/oauth2-server-php-docs/ * 本服务使用 授权码形式 * 授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。 * 这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。 * */ namespace backend\controllers\api; use common\lib\LController; use common\lib\LError; use common\models\admin\AdminModel; use OAuth2\GrantType\AuthorizationCode; use OAuth2\Request; use OAuth2\Response; use OAuth2\Server; use OAuth2\Storage\Pdo; use yii\helpers\Json; use Yii; class OauthController extends LController { public $enableCsrfValidation = false; /** @var Pdo $storage */ public $storage; /** @var Server $server */ public $server; /** @var Request $request */ public $request; /** @var Response $response */ public $response; public function init() { $this->storage = new Pdo([ 'dsn' => 'mysql:host=10.0.80.10;dbname=ylsrc_admin', 'username' => 'root', 'password' => '2Q5@a5X6fh' ], [ 'client_table' => 'src_oauth_clients', 'access_token_table' => 'src_oauth_access_tokens', 'refresh_token_table' => 'src_oauth_refresh_tokens', 'code_table' => 'src_oauth_authorization_codes', 'user_table' => 'src_admin', 'scope_table' => 'src_oauth_scopes', 'public_key_table' => 'src_oauth_public_keys', ]); $this->server = new Server($this->storage); $this->request = Request::createFromGlobals(); $this->response = new Response(); } /** * 获取授权码(测试使用生产环境服务添加到登录接口) * * 获取链接 * GET http://usrc.com/api/oauth/get-code?response_type=code&client_id=1&state=xyz * response_type 必填 请求类型 * client_id 必填 三方授权id * state 必填 回调验证字段 * * 响应方式为跳转到src_oauth_clients表对应id条目设置的redirect_url跳转连接返回第三方应用, 并且携带code * 示例:对应的redirect_url为 https://host.com 那么对应的跳转连接为(state未使用) * https://host.com?code=d53d363349951c29593b722a7d2fb05c054f5e65&state=xyz * */ public function actionGetCode() { $uid = Yii::$app->user->id; if($uid){ $this->server->addGrantType(new AuthorizationCode($this->storage)); // or any grant type you like! $this->server->validateAuthorizeRequest($this->request, $this->response); $this->server->handleAuthorizeRequest($this->request, $this->response, true, $uid); $this->response->send(); }else{ $this->ajaxReturn( LError::NO_PERMISSION, LError::getErrMsgByCode( LError::NO_PERMISSION ), [] ); } } /** * 获取access_toke * 获取链接 * POST http://usrc.com/api/oauth/get-token * data * grant_type 必填 请求类型 authorization_code * client_id 必填 三方授权id * client_secret 必填 三方授权秘钥 * code 必填 上一步获取的授权码 * * return * * { * "access_token": "b2d91c2764bdde79e4f1e92349b969e8ee031e8a", * "expires_in": 3600, * "token_type": "Bearer", * "scope": null, * "refresh_token": "d9293e82c22523ad6500d6b584b484cc3aeb4736" * } */ public function actionGetToken() { $response = $this->server->handleTokenRequest($this->request); $response->send(); } /** * 使用token获取用户信息 * 获取连接 * GET http://usrc.com/api/oauth/get-user-info?access_token=b2d91c2764bdde79e4f1e92349b969e8ee031e8a * * access_token 上一步获取的token * */ public function actionGetUserInfo() { if (!$this->server->verifyResourceRequest($this->request)) { $this->server->getResponse()->send(); }else{ $token = $this->server->getAccessTokenData($this->request); $user = AdminModel::findIdentity($token['user_id']); $data = [ 'id' => $user->id, 'username' => $user->account_name, 'mobile' => $user->mobile, 'email' => $user->email, ]; echo Json::encode($data); } } }
参考文献
OAuth2.0 官方文档 https://oauth.net/2/
OAuth 2.0 Server PHP 官方文档 https://bshaffer.github.io/oauth2-server-php-docs/
OAuth2.0的一个简单解释 阮一峰 http://www.ruanyifeng.com/blog/2019/04/oauth_design.html
OAuth2.0的四种方式 阮一峰 http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html
由于本人能力有限,文章可能有偏差,请批评指出,谢谢!