使用OAuth Server PHP实现OAuth2服务
在现在的网络服务中,OAuth2.0服务已经很普遍了,无论是facebook或者微博的第三方登录,还是手机APP登录,都有很广泛的应用。
它主要的目的如下:
如果用户的照片在A网站,他想要在B网站使用A网站的头像,并不需要向B网站提供自己在A网站的用户名和密码,而直接给B一个Access Token来获取A站的照片
具体流程如下:
1)用户访问网站B
2)B需要验证用户的身份
3)B将用户定向到A网站,用户输入帐号密码登录A网站
4)A网站询问是否要将Authentication的权利给B网站
5)用户告诉A站可以将认证权给B站
6)A网站把Authorization Code发给B站
7)B站用Autorization Code向A站换取Access Token
8)当B站拥有Access Token时,就拥有了用户在A站的一些访问权限
这是典型的Authorization Code Grant,常常运用于网络应用之中
还有Implicit Grant认证方式,这个则省去了Auth Code,开放平台直接返回access_token和有效期,用户ID等数据
这种经常运用于手机客户端或者浏览器插件等没有在线服务器的应用
最后一种是Resource Owner Password Credentials Grant
这种是直接在应用中输入帐号密码,然后由应用XAuth技术将其提交给开放平台并得到Access Token
它经常用于PC可执行程序和手机应用,但由于存在一些争议,开发难度也较大,这里我就先不讨论他
安装
你可以在github上下载OAuth Server PHP,也可以用下列命令下载,不过内容都是一样的
1
2
3
|
mkdir my-oauth2-walkthrough cd my-oauth2-walkthrough git clone https: //github.com/bshaffer/oauth2-server-php.git -b master |
在这之后配置数据库
1
2
3
4
5
6
7
|
CREATE TABLE oauth_clients (client_id VARCHAR( 80 ) NOT NULL, client_secret VARCHAR( 80 ) NOT NULL, redirect_uri VARCHAR( 2000 ) NOT NULL, grant_types VARCHAR( 80 ), scope VARCHAR( 100 ), user_id VARCHAR( 80 ), CONSTRAINT clients_client_id_pk PRIMARY KEY (client_id)); CREATE TABLE oauth_access_tokens (access_token VARCHAR( 40 ) NOT NULL, client_id VARCHAR( 80 ) NOT NULL, user_id VARCHAR( 255 ), expires TIMESTAMP NOT NULL, scope VARCHAR( 2000 ), CONSTRAINT access_token_pk PRIMARY KEY (access_token)); CREATE TABLE oauth_authorization_codes (authorization_code VARCHAR( 40 ) NOT NULL, client_id VARCHAR( 80 ) NOT NULL, user_id VARCHAR( 255 ), redirect_uri VARCHAR( 2000 ), expires TIMESTAMP NOT NULL, scope VARCHAR( 2000 ), CONSTRAINT auth_code_pk PRIMARY KEY (authorization_code)); CREATE TABLE oauth_refresh_tokens (refresh_token VARCHAR( 40 ) NOT NULL, client_id VARCHAR( 80 ) NOT NULL, user_id VARCHAR( 255 ), expires TIMESTAMP NOT NULL, scope VARCHAR( 2000 ), CONSTRAINT refresh_token_pk PRIMARY KEY (refresh_token)); CREATE TABLE oauth_users (username VARCHAR( 255 ) NOT NULL, password VARCHAR( 2000 ), first_name VARCHAR( 255 ), last_name VARCHAR( 255 ), CONSTRAINT username_pk PRIMARY KEY (username)); CREATE TABLE oauth_scopes (scope TEXT, is_default BOOLEAN); CREATE TABLE oauth_jwt (client_id VARCHAR( 80 ) NOT NULL, subject VARCHAR( 80 ), public_key VARCHAR( 2000 ), CONSTRAINT jwt_client_id_pk PRIMARY KEY (client_id)); |
配置
我们来建立一个server.php文件来配置server,这个文件可以被所有的终端来调用。看require once就知道这个文件是平级的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
$dsn = 'mysql:dbname=my_oauth2_db;host=localhost' ; $username = 'root' ; $password = '' ; // 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-php/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 )); |
最后记得配置数据库PDO的用户名和密码
Token控制器
下面,我们将建立一个Token控制器,这个控制器URI将会返回OAuth2的Token给客户端
1
2
3
4
5
|
// 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(); |
测试Token控制器
需要先创建一条记录,来注册一个新的应用
1
|
INSERT INTO oauth_clients (client_id, client_secret, redirect_uri) VALUES ( "testclient" , "testpass" , "http://fake/" ); |
然后用命令行调用
1
|
curl -u testclient:testpass http: //localhost/token.php -d 'grant_type=client_credentials' |
这里的URL只是示例,实地操作要确定能找到这个token.php
如果运行正常,则显示
1
|
{ "access_token" : "03807cb390319329bdf6c777d4dfae9c0d3b3c35" , "expires_in" :3600, "token_type" : "bearer" , "scope" : null } |
资源控制器的建立和测试
你创建了Token,你需要在API中测试它,于是你写了如下代码
1
2
3
4
5
6
7
8
9
|
// 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 if (! $server ->verifyResourceRequest(OAuth2\Request::createFromGlobals())) { $server ->getResponse()->send(); die ; } echo json_encode( array ( 'success' => true, 'message' => 'You accessed my APIs!' )); |
然后运行下面的命令,记得将YOUR_TOKEN替换成刚才得到的token,还有确保URL的正确
1
|
curl http: //localhost/resource.php -d 'access_token=YOUR_TOKEN' |
如果没出问题,则会得到下面的结果
1
|
{ "success" : true , "message" : "You accessed my APIs!" } |
认证控制器的创建和测试
验证控制器是OAuth2的杀手锏,它允许你的平台帮助用户验证第三方应用
它不像第一个例子中直接返回一个Access Token,这里稍微复杂一点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
// include our OAuth2 Server object require_once __DIR__. '/server.php' ; $request = OAuth2\Request::createFromGlobals(); $response = new OAuth2\Response(); // validate the authorize request if (! $server ->validateAuthorizeRequest( $request , $response )) { $response ->send(); die ; } // display an authorization form if ( empty ( $_POST )) { exit (' <form method= "post" > <label>Do You Authorize TestClient?</label><br /> <input type= "submit" name= "authorized" value= "yes" > <input type= "submit" name= "authorized" value= "no" > </form>'); } // print the authorization code if the user has authorized your client $is_authorized = ( $_POST [ 'authorized' ] === 'yes' ); $server ->handleAuthorizeRequest( $request , $response , $is_authorized ); if ( $is_authorized ) { // this is only here so that you get to see your code in the cURL request. Otherwise, we'd redirect back to the client $code = substr ( $response ->getHttpHeader( 'Location' ), strpos ( $response ->getHttpHeader( 'Location' ), 'code=' )+5, 40); exit ( "SUCCESS! Authorization Code: $code" ); } $response ->send(); |
然后在浏览器中打开这个URL
1
|
|
你将会看到一个表单,当你选择yes的时候会弹出你所获得的Authorization Code
现在你可以用这个Authorization Code来刚才建立的token.php获得TOKEN,命令如下
1
|
curl -u testclient:testpass http: //localhost/token.php -d 'grant_type=authorization_code&code=YOUR_CODE' |
就像刚才一样,你获得了一个TOKEN
1
|
{ "access_token" : "6f05ad622a3d32a5a81aee5d73a5826adb8cbf63" , "expires_in" :3600, "token_type" : "bearer" , "scope" : null } |
请在30秒内完成这个操作,因为Authorization Code的有效期只有30秒
用Access Token联系本地用户
当你认证了一个用户并且分派了一个Token之后,你可能想知道彼时到底是哪个用户使用了这个Token
你可以使用handleAuthorizeRequest的可选参数user_id来完成,修改你的authorize.php文件
1
2
|
$userid = 1234; // A value on your server that identifies the user $server ->handleAuthorizeRequest( $request , $response , $is_authorized , $userid ); |
这样一来,用户ID就伴随Token一起存进数据库了
当Token被客户端使用的时候,你就知道是哪个用户了,修改resource.php来完成任务
1
2
3
4
5
6
7
|
if (! $server ->verifyResourceRequest(OAuth2\Request::createFromGlobals())) { $server ->getResponse()->send(); die ; } $token = $server ->getAccessTokenData(OAuth2\Request::createFromGlobals()); echo "User ID associated with this token is {$token['user_id']}" ; |
使用OAuth Server PHP实现OAuth2服务的更多相关文章
- 3行代码快速实现Spring Boot Oauth2服务
这里的3行代码并不是指真的只需要写3行代码,而是基于我已经写好的一个Spring Boot Oauth2服务.仅仅需要修改3行数据库配置信息,即可得到一个Spring Boot Oauth2服务. 项 ...
- 轻松搭建CAS 5.x系列(6)-在CAS Server上增加OAuth2.0协议
概述说明 CAS Server默认搭建出来,客户端程序只能按照CAS自身的协议接入.CAS的强大在于,有官方的插件,可以支持其他的协议.本章节就让CAS Server怎么增加OAuth2.0的登录协议 ...
- ArcGIS API for JavaScript(2)-ArcGIS Server发布要素图层服务
1.前言 上一篇该系列的文章我们主要讲了一下基础Web地图搭建,这篇我们主要讲一下ArcGIS Server发布服务,并且如何调用服务.将自己的数据加载到Web地图当中来,实现Web端浏览数据. 2. ...
- Atitit Server Side Include ssi服务端包含规范 csi esi
Atitit Server Side Include ssi服务端包含规范 csi esi 一.CSI (Client Side Includes) 1 1.1. 客户端包含1 1.2. Ang ...
- ArcGIS Server新建主题图服务的步骤
ArcGIS Server新建主题图服务的步骤: 1.修改数据库模型图(PowerDesigner) 2.修改lygis.gdb文件数据库(发布时可以快速把表结构从gdb数据库拷贝到客户服务器的SDE ...
- 以Server模式启动Derby服务竟然抛套接字权限异常
以Server模式启动Derby服务竟然抛套接字权限异常:access denied ("java.net.SocketPermission" "localhost:15 ...
- OpenLayers调用arcgis server发布的地图服务
有两种方式可以调用arcgis server发布的地图服务,一种是rest,一种是wms. 地图的投影为900913,arcgis server为10.0版本,地图服务的空间参考为3857. 与 ...
- OpenLayers调用ArcGIS Server发布的WFS服务
OpenLayers调用ArcGIS Server发布的WFS服务 原创: 蔡建良 2013-08-20 一. 开发环境 1) Openlayers2.13+arcgis server9.3 2) W ...
- 异步tcp通信——APM.Server 消息推送服务的实现
消息推送服务 服务器推送目前流行就是私信.发布/订阅等模式,基本上都是基于会话映射,消息对列等技术实现的:高性能.分布式可以如下解决:会话映射可采用redis cluster等技术实现,消息对列可使用 ...
随机推荐
- C#读取对象实例的值和对对象的属性自动赋值方法
using System; using System.Data; using System.Reflection; namespace DBUtility { /// <summary> ...
- jQuery函数继承 $.extend, $.fn.extend
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- NLog自定义字段写入数据库表,示例
//自定义字段写入NLog日志 private void saveNLog(InvokeLogModel model) { LogEventInfo ei = new LogEventInfo(); ...
- 菜鸟学SSH(十三)——Spring容器IOC解析及简单实现
最近一段时间,“容器”两个字一直萦绕在我的耳边,甚至是吃饭.睡觉的时候都在我脑子里蹦来蹦去的.随着这些天一次次的交流.讨论,对于容器的理解也逐渐加深.理论上的东西终归要落实到实践,今天就借助Sprin ...
- EditText: 自定义EditText 触摸时无法获取焦点
写了一个自定义View,继承EditText,但是在触摸时无法获取到焦点. 在XML中添加 android:focusableInTouchMode="true" 设置触摸时可以获 ...
- (原创)谈谈boost.asio的异步发送
在上一篇博文中提到asio的异步发送稍微复杂一点,有必要单独拿出来说说.asio异步发送复杂的地方在于: 不能连续调用异步发送接口async_write,因为async_write内部是不断调用asy ...
- FFmpeg Basics学习笔记(1)ffmpeg基础
1 FFmpeg的由来 FFmpeg缩写中,FF指的是Fast Forward,mpeg是 Moving Pictures Experts Group的缩写.官网:ffmpeg.org 编译好的可执行 ...
- 将String转换成InputStream
String str = "";//add your string contentInputStream inputStream = new ...
- Leetcode:Interleaving String 解题报告
Interleaving StringGiven s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For ...
- Python(九)之网络编程
一般的网络通信: Python中利用socket模块实现网络主机间通讯: socket.socket(family,type) family:套接字类型 AF_INET AF_UNIX type: S ...