一笑·科奉

php oauth2 server 搭建方法及其简单应用(bshaffer/oauth2-server-php)

作者: 一笑, 写于: 2017-09-09 09:42:26

自己写代码实现oauth2 server太累,直接在github.com中搜索oauth2 server有现成的,但搜索结果出来后,有选择综合症的我又迷茫了,因仅PHP语言的相关资源就有306个之多,其中收藏比较多的有两个:thephpleague/oauth2-server(2年前发布更新至今)和bshaffer/oauth2-server-php(5年前发布更新至今),我选择了年份比较久的bshaffer/oauth2-server-php(当然,有选择障碍的我,也试了thephpleague/oauth2-server,文章链接:https://www.kefong.com/post/46.html  )

image.png

1、首先准备一个可以随意支配的,支持PHP的WEB站点和MYSQL数据库

2、下载OAuth2

各种语言的代码:https://oauth.net/code/,我下载的是PHP版本的代码:

https://github.com/bshaffer/oauth2-server-php 

image.png

image.png

下载下来的文件

image.png

在项目目录(事先建立好WEB站点,需要支持PHP)下,新建文件夹“oauth2-server”,将刚才下载的文件全部解压到此目录中。

image.png

3、在根目录下,新建文件index.php(和刚才建的oauth2-server文件夹平级)(此步骤可以略过

image.png

<?php
require_once('oauth2-server/src/OAuth2/Autoloader.php');
OAuth2\Autoloader::register();

$dsn = 'mysql:dbname=t3ex_oauth2;host=127.0.0.1';
$username = 'root';
$password = '123456';

$storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));
$server = new OAuth2\Server($storage);
$server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage)); //or any grant type you like!
$server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();

4、访问这个网站,成功报error(难道是server端就只如此了,那如何使用呢?又迷茫了。)

image.png

从网上搜了半天,还是官网的说明文档,指了条明路,终于可以据需往下走了。

5、导入数据库(参考资料:http://bshaffer.github.io/oauth2-server-php-docs/cookbook/  )

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)
);

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
);

6、在站点根目录下新建server.php(创建和配置OAuth2 server的实例,接下来的)

$dsn      = 'mysql:dbname=t3ex_oauth2;host=127.0.0.1';
$username = 'root';
$password = '123456';

// error reporting (this is a demo, after all!)
ini_set('display_errors',1);error_reporting(E_ALL);

// Autoloading (composer is preferred, but for this example let's just do this)
require_once('oauth2-server/src/OAuth2/Autoloader.php');
OAuth2\Autoloader::register();

// $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost"
$storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));

// Pass a storage object or array of storage objects to the OAuth2 server class
$server = new OAuth2\Server($storage);

// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));

// Add the "Authorization Code" grant type (this is where the oauth magic happens)
$server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage));

7、新建token.php(post方法访问这个页面,可以获取令牌:access_token)

// include our OAuth2 Server object
require_once __DIR__.'/server.php';

// Handle a request for an OAuth2.0 Access Token and send the response to the client
$server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();

8、在测试是否获取令牌之前,我们需要在oauth_clients表中加一条数据,可执行如下SQL:

INSERT INTO oauth_clients (client_id, client_secret, redirect_uri) VALUES ("testclient", "testpass", "http://fake/");

9、然后在浏览器录入:http://t3ex-oauth.lp/token.php

image.png

额,告诉我要使用post传送必须的数据,传些什么数据呢?打开他给的error_uri,可以看到,需要post传以下值:

image.png

网上找到,response_type有如下值:

grant_type

说明

authorization_code

标准的Server授权模式

password

基于用户密码的授权模式

client_credentials

基于APP密钥的授权模式

refresh_token

刷新accessToken

那就方便了我们先试试client_credentials(其实是我试了其他的,都报错。。。),可以借用命令行工具curl(windows下需安装此命令,点此看如何安装curl)来测试下,获取access_token

curl http://t3ex-oauth.lp/token.php -d "grant_type=client_credentials&client_id=testclient&client_secret=testpass"

运行命令后,看我们已经获取到access_token了,太帅了。

image.png

如果你喜欢用可视界面测试的话,推荐使用postman这个chrome插件,效果和命令行获取到的一样(如下图)

image.png

10、拿到access_token后,我们就要验证下这个令牌(access_token)是否有用啦,创建资源控制器文件:resource.php

// include our OAuth2 Server object
require_once __DIR__.'/server.php';

// Handle a request to a resource and authenticate the access token
if (!$server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
	$server->getResponse()->send();
	die;
}
echo json_encode(array('success' => true, 'message' => 'You accessed my APIs!'));

然后访问网址:http://t3ex-oauth.lp/resource.php?access_token=YOUR_TOKEN (如下图)

看成功返回true啦!兴奋啊!

image.png

为了验证access_token是否起了作用,我们可以用一个错误的和过期的access_token测试下。报错了。完美!

image.png

image.png

到这一步,我们已经可以想象到将来的应用场景了:

首先:第三方应用可以使用我们提供的client_id和client_secret,获取到access_token

然后:再根据这个access_token访问我们的API,只要在access_token过期之前重新获取,就可以一直有权限访问我们的API了(我们的API只要拿到access_token后,马上验证下是否有效就可以了,如果有效就返回授权后的资源,并且将此access_token记录session或其他缓存中,只要在有效期内就不用再去数据库验证了)

PS:如果我们的“第三方应用”是client js写的,而且是个多用户的APP,则每个USER都需要被分配到一个client_id和client_secret(要与第三方应用的用户名密码绑定),且app自己要把USER的登录信息写到cookie(以便过期后再次获取access_token)

这样总感觉哪里不对。这样如何实现多应用公用登录呢?第三方应用每个用户都分配一个client_id和client_secret?如何知道使用哪个UID的资源呢?多大的权限呢?

OAuth2支持很多授权模式,就像password模式还没有再用,下篇文章我们就一起研究下,一个第三方应用一个client_id,而不是每个用户都分配一个client_id的方法。

快速链接:vue + thinkphp5(API) + oauth 2.0实现系统登录


分类: OAuth 2.0, 浏览: 3576, 评论: 0
原创文章转载请注明:转自《一笑·科奉》 原文地址:https://www.kefong.com/post/6.html