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

 
posted @ 2020-09-10 21:11  隆冬之夜99  阅读(1491)  评论(0编辑  收藏  举报