tp5.1框架搭建OAuth2.0服务端

基于thinkphp5.1框架搭建OAuth2.0服务端_Linux不归路-CSDN博客

 

https://segmentfault.com/a/1190000016408592?utm_source=tag-newest

OAuth是用于服务端与客户端授权登录的协议,OAuth2.0是OAuth的第二个版本,关于OAuth2.0的基础知识,可以阅读阮一峰的一篇博文,对OAuth2.0的介绍非常详细,只要理解了OAuth2.0的授权过程,在自己网站实现OAuth2.0并不复杂。

本文将讲解如何基于thinkphp5.1的框架实现OAuth2.0的服务端。


1 环境搭建

首先确保你已经搭建好了服务器,并且已经能够正常访问你的服务器。我的环境Xampp+thinkphp5.1.


2 安装OAuth2.0 php包

你页根据OAuth2.0的协议自己去实现代码,但是最快捷最安全最可靠的方法当然是移植第三方OAuth2.0包。OAuth官网提供了很多第三方包,详见网站Code — OAuth, 如下图,因为thinkphp是基于php语言,因此我选择了PHP下第一个。

点击PHP OAuth2 Server会跳入源码下载库,将其下载到电脑即可。

下载后解压,我们只需要将里面/src/OAuth文件夹整个拷贝到tp5/extend/目录下,就可以自动注册对应的命名空间。之后我们就可以使用\OAuth2\...的方式去使用OAuth里面的任何方法。


3 实现OAuth服务端


3.1 创建数据库

由于我们之前下载的OAuth包有用到很多数据表,所以需要按照其要求创建好数据表,创建代码如下:

-- 你可使用相应的数据库引擎:MySQL / SQLite / PostgreSQL / MS SQL Server
-- 数据库:oauth_test
-- 细调过表相关结构,不过你也可以参考官方:http://bshaffer.github.io/oauth2-server-php-docs/cookbook/
 
DROP TABLE IF EXISTS `oauth_access_tokens`;
CREATE TABLE `oauth_access_tokens` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `access_token` varchar(40) NOT NULL,
  `client_id` varchar(80) NOT NULL,
  `user_id` varchar(80) DEFAULT NULL,
  `expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `scope` text NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `IDX_ACCESS_TOKEN` (`access_token`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
 
-- ----------------------------
-- Table structure for oauth_authorization_codes
-- ----------------------------
DROP TABLE IF EXISTS `oauth_authorization_codes`;
CREATE TABLE `oauth_authorization_codes` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `authorization_code` varchar(40) DEFAULT '',
  `client_id` varchar(80) DEFAULT '',
  `user_id` varchar(80) DEFAULT '0',
  `redirect_uri` varchar(2000) DEFAULT '',
  `expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `scope` text,
  `id_token` varchar(1000) DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `IDX_CODE` (`authorization_code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
-- ----------------------------
-- Records of oauth_authorization_codes
-- ----------------------------
 
-- ----------------------------
-- Table structure for oauth_clients
-- ----------------------------
DROP TABLE IF EXISTS `oauth_clients`;
CREATE TABLE `oauth_clients` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `client_id` varchar(80) DEFAULT '',
  `client_secret` varchar(80) DEFAULT '',
  `client_name` varchar(120) DEFAULT '',
  `redirect_uri` varchar(2000) DEFAULT '',
  `grant_types` varchar(80) DEFAULT '',
  `scope` varchar(4000) DEFAULT '',
  `user_id` varchar(80) DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `IDX_APP_SECRET` (`client_id`,`client_secret`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
 
-- ----------------------------
-- Records of oauth_clients
-- ----------------------------
INSERT INTO `oauth_clients` VALUES ('1', 'testclient', '123456', '测试demo', 'http://sxx.qkl.local/v2/oauth/cb', 'authorization_code refresh_token', 'basic get_user_info upload_pic', '');
 
-- ----------------------------
-- Table structure for oauth_jwt 
-- ----------------------------
DROP TABLE IF EXISTS `oauth_jwt`;
CREATE TABLE `oauth_jwt` (
  `client_id` varchar(80) NOT NULL,
  `subject` varchar(80) DEFAULT NULL,
  `public_key` varchar(2000) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
-- ----------------------------
-- Records of oauth_jwt
-- ----------------------------
 
-- ----------------------------
-- Table structure for oauth_public_keys
-- ----------------------------
DROP TABLE IF EXISTS `oauth_public_keys`;
CREATE TABLE `oauth_public_keys` (
  `client_id` varchar(80) DEFAULT NULL,
  `public_key` varchar(2000) DEFAULT NULL,
  `private_key` varchar(2000) DEFAULT NULL,
  `encryption_algorithm` varchar(100) DEFAULT 'RS256'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
-- ----------------------------
-- Records of oauth_public_keys
-- ----------------------------
 
-- ----------------------------
-- Table structure for oauth_refresh_tokens
-- ----------------------------
DROP TABLE IF EXISTS `oauth_refresh_tokens`;
CREATE TABLE `oauth_refresh_tokens` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `refresh_token` varchar(40) NOT NULL,
  `client_id` varchar(80) NOT NULL DEFAULT '',
  `user_id` varchar(80) DEFAULT '',
  `expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `scope` text,
  PRIMARY KEY (`id`),
  UNIQUE KEY `IDX_REFRESH_TOKEN` (`refresh_token`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
 
-- ----------------------------
-- Table structure for oauth_scopes
-- ----------------------------
DROP TABLE IF EXISTS `oauth_scopes`;
CREATE TABLE `oauth_scopes` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `scope` varchar(80) NOT NULL DEFAULT '',
  `is_default` tinyint(1) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
 
-- ----------------------------
-- Records of oauth_scopes
-- ----------------------------
INSERT INTO `oauth_scopes` VALUES ('1', 'basic', '1');
INSERT INTO `oauth_scopes` VALUES ('2', 'get_user_info', '0');
INSERT INTO `oauth_scopes` VALUES ('3', 'upload_pic', '0');
 
-- ----------------------------
-- Table structure for oauth_users  该表是Resource Owner Password Credentials Grant所使用
-- ----------------------------
DROP TABLE IF EXISTS `oauth_users`;
CREATE TABLE `oauth_users` (
  `uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(80) DEFAULT '',
  `password` varchar(80) DEFAULT '',
  `first_name` varchar(80) DEFAULT '',
  `last_name` varchar(80) DEFAULT '',
  `email` varchar(80) DEFAULT '',
  `email_verified` tinyint(1) DEFAULT '0',
  `scope` text,
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
 
-- ----------------------------
-- Records of oauth_users
-- ----------------------------
INSERT INTO `oauth_users` VALUES ('1', 'qkl', '123456', 'kl', 'q', '', '', '');

3.2 创建控制器 

注意:需要把表:oauth_clients里的字段:grant_types改为grant_type

需要在tp5/application/index/controller下创建一个控制器,命名为OAuth.php,写入以下代码,控制器就创建完成了。

 
  1. <?php

  2. namespace app\index\controller;

  3. class OAuth extends \think\Controller

  4. {

  5. }


3.3 实现authorize

OAuth 2.0的运行流程如下图。

所以第一步是实现authorization。

我们在之前创建好的控制器中添加一个函数authorize()

代码如下(注意,dbname需要换成你自己的数据库的名字,下同):

 
  1. <?php

  2. namespace app\index\controller;

  3. class OAuth extends \think\Controller

  4. {

  5. public function authorize()

  6. {

  7. global $server;

  8. $dsn = 'mysql:dbname=XXX;host=127.0.0.1';

  9. $username = 'root';

  10. $password = '';

  11. \OAuth2\Autoloader::register();

  12. // $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost"

  13. $storage = new \OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));

  14. // Pass a storage object or array of storage objects to the OAuth2 server class

  15. $server = new \OAuth2\Server($storage);

  16. // Add the "Client Credentials" grant type (it is the simplest of the grant types)

  17. $server->addGrantType(new \OAuth2\GrantType\ClientCredentials($storage));

  18. // Add the "Authorization Code" grant type (this is where the oauth magic happens)

  19. $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($storage));

  20. $request = \OAuth2\Request::createFromGlobals();

  21. $response = new \OAuth2\Response();

  22. // validate the authorize request

  23. if (!$server->validateAuthorizeRequest($request, $response)) {

  24. die;

  25. }

  26. // display an authorization form

  27. if (empty($_POST)) {

  28. exit('

  29. <form method="post">

  30. <label>Do You Authorize TestClient?</label><br />

  31. <input type="submit" name="authorized" value="yes">

  32. <input type="submit" name="authorized" value="no">

  33. </form>');

  34. }

  35. // print the authorization code if the user has authorized your client

  36. $is_authorized = ($_POST['authorized'] === 'yes');

  37. $server->handleAuthorizeRequest($request, $response, $is_authorized);

  38. if ($is_authorized) {

  39. // this is only here so that you get to see your code in the cURL request. Otherwise, we'd redirect back to the client

  40. $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40);

  41. exit("SUCCESS! Authorization Code: $code");

  42. }

  43. $response->send();

  44. }

  45. }

在tp5/route/route.php中创建相应路由,post方法和get方法都创建

 
  1. Route::get('authorize', 'OAuth/authorize');

  2. Route::post('authorize', 'OAuth/authorize');

接下来验证创建的authorize是否成功,通过以下链接去访问,在浏览器中输入以下链接,回车后就会显示一个验证表单,当你点击yes按钮后,如果窗口显示一串字符,那么就表示authorize创建成功了,这串字符就是code,接下来需要通过这个code去获取token。

http://gio.com/authorize?response_type=code&client_id=testclient&state=xyz

3.4 实现token申请方法

在OAuth.php控制器中添加函数token(),代码如下

 
  1. public function token(){

  2. global $server;

  3. $dsn = 'mysql:dbname=XXX;host=127.0.0.1';

  4. $username = 'root';

  5. $password = '';

  6. \OAuth2\Autoloader::register();

  7. // $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost"

  8. $storage = new \OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));

  9. // Pass a storage object or array of storage objects to the OAuth2 server class

  10. $server = new \OAuth2\Server($storage);

  11. // Add the "Client Credentials" grant type (it is the simplest of the grant types)

  12. $server->addGrantType(new \OAuth2\GrantType\ClientCredentials($storage));

  13. // Add the "Authorization Code" grant type (this is where the oauth magic happens)

  14. $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($storage));

  15. // Handle a request for an OAuth2.0 Access Token and send the response to the client

  16. $server->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send();

  17. }

在tp5/route/route.php中创建相应路由,post方法和get方法都创建

 
  1. Route::get('token', 'OAuth/token');

  2. Route::post('token', 'OAuth/token');

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

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

接下来从CMD运行以下内容,注意:code的值需要换成你上一步生成的code

curl -X POST http://**.cn/token -d "grant_type=client_credentials&code=2d7257fadddad33404b850899a4417d50e&client_id=testclient&client_secret=123456"

如果成功的话,你应该会得到access token,如下内容

{"access_token":"6f05ad622a3d32a5a81aee5d73a5826adb8cbf63","expires_in":3600,"token_type":"bearer","scope":null}

3.5 实现Resource获取

 在OAuth.php控制器中添加函数resource(),代码如下

 
  1. public function resource()

  2. {

  3. // include our OAuth2 Server object

  4. global $server;

  5. $dsn = 'mysql:dbname=XXX;host=127.0.0.1';

  6. $username = 'root';

  7. $password = '';

  8. \OAuth2\Autoloader::register();

  9. // $dsn is the Data Source Name for your database, for exmaple "mysql:dbname=my_oauth2_db;host=localhost"

  10. $storage = new \OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));

  11. // Pass a storage object or array of storage objects to the OAuth2 server class

  12. $server = new \OAuth2\Server($storage);

  13. // Add the "Client Credentials" grant type (it is the simplest of the grant types)

  14. $server->addGrantType(new \OAuth2\GrantType\ClientCredentials($storage));

  15. // Add the "Authorization Code" grant type (this is where the oauth magic happens)

  16. $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($storage));

  17. // Handle a request to a resource and authenticate the access token

  18. if (!$server->verifyResourceRequest(\OAuth2\Request::createFromGlobals())) {

  19. $server->getResponse()->send();

  20. die;

  21. }

  22. echo json_encode(array('success' => true, 'message' => 'You accessed my APIs!'));

  23. }

在tp5/route/route.php中创建相应路由,post方法和get方法都创建

 
  1. Route::get('resource', 'OAuth/resource');

  2. Route::post('resource', 'OAuth/resource');

验证:通过CMD运行以下内容(将access token的值换成上一次获取的access token):

curl http://localhost/resource.php -d 'access_token=YOUR_TOKEN'

如果成功,将会获得以下响应:

{"success":true,"message":"You accessed my APIs!"}


4 总结

至此,OAuth所有相关的都实现了,整个过程就是客户端去想服务端申请token,然后拿着这个token向服务端获取资源的过程。后续有什么不明白的地方,大家可以在下面评论,我有时间会回答大家。关于oauth2-server-php库的更多详情,大家可以访问OAuth2 Server PHP

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xingxingwuxin

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值