基于 PHP & MySQL 搭建OAuth Server
2015-11-13 08:44
1156 查看
现在越来越多开放的互联网公司提供对外的 API 接口,使得第三方应用开发人员可以开发基于该平台接口的应用程序。国外有Twitter、Flicker
Service等;国内的,像腾讯微博开放平台、新浪微博开放平台等等。
这些平台接口的认证方式,无一例外的,都采取了 OAuth 来实现(Twitter原来使用的是Basic Auth方式,后来全面转向OAuth)。
那么,OAuth 是什么?OAuth认证又有什么好处呢?
OAuth 是什么
关于OAuth的定义,在 OAuth官网 的首页上,有一行大大的文字说明:
(OAuth) 是一个开放协议,它以一种简单、标准的方式实现对桌面和 Web 的应用程序的安全 API 认证。
OAuth 1.0 协议(中文版 | 英文版)这样介绍OAuth:“OAuth
协议致力于使网站和应用程序(统称为消费方)能够在无须用户透露其认证证书的情况下,通过 API 访问某个web服务(统称为服务提供方)的受保护资源。更一般地说,OAuth 为 API 认证提供了一个可自由实现且通用的方法”。
关于 OAuth 的用途,OAuth 1.0 协议(中文版 | 英文版)上举了一个例子:某打印服务提供商
printer.example.com(消费方),希望在无须用户提供其照片存储站点密码的情况下,访问用户储存在 photos.example.net(服务提供方)上的个人照片。
假如没有 OAuth,用户必须要向消费方也就是 printer 提供自己在服务提供商 photos 上的授权资料(通常是密码),消费方利用这个授权资料,通过服务提供方的权限验证,从而获得要打印的图片。这样看似没有什么问题。但是用户的授权资料,通常在这一过程中被消费方有意或者无意地窃取或泄露,从而对用户和服务提供方的信息安全造成威胁。
而如果利用 OAuth 进行此过程的授权,用户的授权资料并不会传递给第三方(也就是消费方,通常是App应用),而消费方只需要将用户引导至服务提供方的授权页面进行授权,使得消费方获得访问受限资源的权限即可。而在此过程中,用户授权过程是在服务提供方进行的,消费方并不会直接接触到用户的授权资料,因此一般不会造成用户授权资料的泄密,从而既保证了用户和服务提供方的信息安全,又使得消费方完成了对受限资源的读取。可谓一举三得。
个人对 OAuth 授权过程的理解:服务提供方 SP 好比一个封闭院子,只有持卡人才能进入,用户 U 就是持卡人之一。而消费方 C 没有持卡,通常情况下是不能进入的。但是有一天,由于特殊原因,U 需要 C 帮忙去 SP 那里取一样东西。这个时候问题就来了: C 没有持卡,不能进去院子,而 U 又不能把卡直接给 C (卡上面有很多个人机密信息,不方便外泄哦)。怎么办呢?
哦,对了,U 可以带着 C 去门口,告诉SP:这个人是我认识的,他需要进去帮我拿我的一样东西,请予放行。这样,U 既不用将带有个人私密信息的门卡交给 C,C 也通过验证拿到了属于 U 的东西。
有的人要问了,是不是下次 C 想要再进 SP 的拿 U 的东西的话,是不是就不用 U 的指引了呢?人类社会的情况通常是这样的。可惜,在 HTTP 的世界里,由于 HTTP 是无状态的协议,因此,SP 仍然不会认识 C。所以,每次 C 想要取东西,总是需要 U 的指引。是不是很麻烦呢?呵呵。但是为了安全,麻烦一点又有什何妨!
上面介绍了 OAuth 认证的基本思路,如果你还不理解,可以参考 OAuth认证流程图, 或者查看腾讯微博关于OAuth认证的介绍。OAuth
官方网站就有一篇文档教程《OAuth入门指南》,不过没有中文版本。有兴趣同学的也可以自己看看。
OAuth 认证授权有以下几个特点:
1. 简单:不管是 OAuth 服务提供者还是应用开发者,都很容易于理解与使用;
2. 安全:没有涉及到用户密钥等信息,更安全更灵活;
3. 开放:任何服务提供商都可以实现 OAuth,任何软件开发商都可以使用 OAuth;
那么下面我们就作为服务提供商角色,来实现 OAuth 认证服务器的安装和搭建。
其实,很多先行者已经开发出了很多的 OAuth 消费方代码(客户端)和服务提供方代码(服务端),这里是它们的一些列表,其中包含了 .NET (C#/VB.NET), ColdFusion, Java, Javascript, Jifty, Objective-C, OCaml, Perl, PHP, Python,
Ruby, Erlang 和其他语言的一些实现。
通过 Google,我找到了一个开源的 OAuth 服务端代码和消费方开源代码库项目——oauth-php. 我们就借此来实现。关于OAuth,项目主页的介绍是: OAuth Consumer And Server Library For PHP. 它包含一个完整实现的可扩展的OAuth存储,支持
MySQL/MySQLi, Postgresql, PDO 和 Oracle 等多种存储方式。
它实现了以下方法:
认证进来的请求
为出去的请求签名
使用 body 为请求签名
为多用户管理消费方的 key 和 token(服务端和消费端)
记录经过类库处理的进出的请求(可以在数据库中进行可选配置)
很多网站都在使用oauth-php, 包括荷兰阿姆斯特丹Mediamatic Lab实验室出品的anyMeta CMS. 目前,oauth-php 的代码主要由Corollarium Technologies 负责维护。
为你的服务器增加 OAuth 非常简单。你需要检查进来的请求中 OAuth 认证细节。首先,我们需要四个控制器 controller 文件:
oauth_register.php 使消费方用户获得 key 和密钥
request_token.php 返回一个未认证的 request token
authorize.php 认证一个request token
access_token.php 将认证后的 request token 置换为 access token
以下的例子,假设使用的数据存储器是MySQL。你也可以使用其他数据库——当你第一次使用 OAuthStore 实例的时候指定一个参数,告诉它你要使用的数据库。
这就是假设在存储器目录,你有一个名为 OAuthStoremystore.php 文件。在这里我们使用 OAuthStoreMySQL.php 文件来实现。这也就是说,我们在实例化 OAuthStore 的时候,需要这样做:
然后,在每个请求被处理之前,都可以检查其是否带有 OAuth 认证信息:
每个消费方都使用 key 和密钥的组合和 token 和 token 密钥的组合来为它的请求进行签名。而在此之前,消费方必须要先获取属于它的消费方 key 和消费方密钥。 oauth_register.php 就是负责分发消费方 key 和密钥的控制器文件。
如果你想要更新之前注册的消费方身份,提供消费方id,key 和 secret 。key 和 secret 在更新操作完成之前不会进行改变。
你还可以请求一个特定用户注册的所有消费方列表:
request_token.php 这个控制器文件负责返回请求 token(未认证的 request token)。当消费方获取了 key 和 secret 之后,它就可以向服务器端请求未认证的 request token 了:
authorize.php 控制器文件负责认证一个用户请求 token。这个控制器负责询问用户是否允许消费方访问他的账户。如果允许,那么消费方将可以使用 request token 换取 access token。必须要保证用户在访问下面的代码之前是登录状态。OAuthServer 服务器使用 SESSION 存储一些 OAuth 状态信息,所以必须要开启seesion会话(要么是 session_start 函数,要么就是自动开启)。
access_token.php 控制器文件负责将认证的request token换成access token。access token 可以被用来为请求签名。
看完本文,如果还是一头雾水,不知道如何下手,可以继续阅读《基于PHP & MySQL 搭建 OAuth Server》。
接上一篇《一步一步搭建 OAuth 认证服务器》的文章,其实也就是介绍了一下 OAuth 的理解和 oauth-php 这个开源的项目,并没有做出一个演示。今天这篇文章就来做一个Demo,我们基于
PHP 来搭建一个 OAuth认证服务器。开始吧!
为了方便理解,可以先看一下在 OAuth 认证过程中的几个关键术语,这也是RFC5849 中 “1.1. Terminology” 小节的内容。也可以查看其中文版本。
想了一下,没有想到好的应用场景,干脆就使用 RFC5849 中的例子吧。这个例子大概的意思是:
首先,我们再虚拟机上面搭建三个虚拟主机。我这里搭建的三个主机是:
配合上面介绍的应用场景,www.service.com 相当于网站A,而 www.demo.com 则相当于网站B.
接下来,我们为网站 A 虚拟一个用户 Jane,并将其用户名和密码以及她的照片保存在 MySQL 数据库中。
先创建一个数据库,名曰:photo, 在其中新建一个表user:
用户有了,现在给用户创建一个表,用来存储用户照片。新建一个表“image”:
数据表有了,现在填充一些数据:
由于 auth.service.com 认证服务器需要提供应用程序认证服务,所以需要创建一个表存储应用程序信息。实际上,还需要一些其他的相关的数据表。
我们这里使用的是 MySQL 数据库,打开浏览器,访问 http://auth.service.com/oauth-php/library/store/mysql/install.php 来进行数据表的安装。事先需要编辑 install.php 进行数据库配置。安装完毕,请将该文件的数据库连接部分重新注释掉。
下面来实现OAUTH服务器端的应用注册功能。
首先在 oauth.service.com 服务器下新建一个 config.inc.php 文件,文件内容如下:
该文件的主要作用是保存数据库连接信息。然后继续新建一个 “oauth_register.php” 文件,文件内容如下:
这时候,通过浏览器访问:http://auth.service.com 就可以自动注册一个应用(其实就是一个消费方Client)。并且将该应用的 App Key 和 App Secret呈现给你。下面 www.demo.com 站点将使用这2个字符串进行认证。所以现在先把这两个值保存起来备用。
看到的页面应该类似于:
这样,消费方注册功能就完成了。
接下来,消费方 www.demo.com 就可以使用这个 App Key 和 App Secret,向认证服务器请求未授权的 Request token 了。这一步需要做两件事情:① 消费方 www.demo.com 向 OAuth Server 也就是 auth.service.com 请求未授权的 Request token;② OAuth Server 处理消费方的请求,生成并将未授权的 Request token 返回给消费方;
先来实现第②件任务。
在认证服务器 auth.service.com 的根目录下新建一个文件”request_token.php”, 文件内容是:
现在认证服务器已经可以响应消费方请求“未授权的token”了。
这里要特别注意一点,如果测试的时候,消费方和服务提供方在同一台服务器,就像我现在的情况,三个服务器都在同一个虚拟机里,那么要注意,客户端请求的时候,可能发生找不到主机的问题。为啥?因为服务器找不到虚拟的 auth.service.com 认证服务器。怎么解决呢?
Windows下面,我们可以设置 hosts 主机表文件,使某一域名的指向某一固定IP地址。Linux下面也有类似的主机表文件,它的位置是 /etc/hosts,接下来如何做,这里就不用讲啦。
现在来实现第①件任务。
首先在消费方数据库服务器将认证服务器添加到消费方的 OAuthStore 中。这里的数据库安装方式与服务方相同,不再赘述。
然后,我们再消费方服务器 www.demo.com 的根目录添加一个 “config.inc.php” 文件,保存消费方自己的数据库连接信息。我这里由于使用的是虚拟主机,恰好消费方和认证服务器的数据库连接参数是一样的。实际情况可能不是这样。文件的内容与上面的类似:
然后,在消费方服务器根目录继续添加一个文件,add_server.php, 用来向消费方的数据库中存储认证服务器的信息。其实一般的,这个信息可能会直接写在配置文件里,不过,oauth-php提供了更加强大的数据库的存储方案而已。该文件的内容是:
这样,通过浏览器访问一下该文件,http://www.demo.com/add_server.php, 服务器的相关信息就会被保存起来了。用于生产环节时,这里可能是一个简单的管理系统,可以用来管理认证服务器列表。注意,上面文件里的 key 和 secret 正是我们之前在认证服务器 http://auth.service.com 注册消费方应用时得到的。
有了认证服务器的相关信息,我们现在可以去获取“未认证的token”了。在 www.demo.com 根目录新建一个文件 index.php:
现在,通过浏览器访问 www.demo.com/index.php页面,然后点击页面上的“Click Me”按钮,开始向auth.service.com服务器请求“未授权的token”。如果最后结果显示类似于:
那么恭喜你,获取“未授权的token”这一步,已经顺利完成了。
接下来,根据 OAuth 验证的流程,应该是重定向用户浏览器到 auth.service.com 进行 token 授权。
在 auth.demo.com 服务器根目录新建一个文件 authorize.php, 代码如下:
如果用户未登录,则要求先行登陆才能进行授权操作。
http://blog.163.com/da7_1@126/blog/static/10407267820119303659937/
Service等;国内的,像腾讯微博开放平台、新浪微博开放平台等等。
这些平台接口的认证方式,无一例外的,都采取了 OAuth 来实现(Twitter原来使用的是Basic Auth方式,后来全面转向OAuth)。
那么,OAuth 是什么?OAuth认证又有什么好处呢?
OAuth 是什么
关于OAuth的定义,在 OAuth官网 的首页上,有一行大大的文字说明:
1 | An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications. |
OAuth 1.0 协议(中文版 | 英文版)这样介绍OAuth:“OAuth
协议致力于使网站和应用程序(统称为消费方)能够在无须用户透露其认证证书的情况下,通过 API 访问某个web服务(统称为服务提供方)的受保护资源。更一般地说,OAuth 为 API 认证提供了一个可自由实现且通用的方法”。
关于 OAuth 的用途,OAuth 1.0 协议(中文版 | 英文版)上举了一个例子:某打印服务提供商
printer.example.com(消费方),希望在无须用户提供其照片存储站点密码的情况下,访问用户储存在 photos.example.net(服务提供方)上的个人照片。
假如没有 OAuth,用户必须要向消费方也就是 printer 提供自己在服务提供商 photos 上的授权资料(通常是密码),消费方利用这个授权资料,通过服务提供方的权限验证,从而获得要打印的图片。这样看似没有什么问题。但是用户的授权资料,通常在这一过程中被消费方有意或者无意地窃取或泄露,从而对用户和服务提供方的信息安全造成威胁。
而如果利用 OAuth 进行此过程的授权,用户的授权资料并不会传递给第三方(也就是消费方,通常是App应用),而消费方只需要将用户引导至服务提供方的授权页面进行授权,使得消费方获得访问受限资源的权限即可。而在此过程中,用户授权过程是在服务提供方进行的,消费方并不会直接接触到用户的授权资料,因此一般不会造成用户授权资料的泄密,从而既保证了用户和服务提供方的信息安全,又使得消费方完成了对受限资源的读取。可谓一举三得。
个人对 OAuth 授权过程的理解:服务提供方 SP 好比一个封闭院子,只有持卡人才能进入,用户 U 就是持卡人之一。而消费方 C 没有持卡,通常情况下是不能进入的。但是有一天,由于特殊原因,U 需要 C 帮忙去 SP 那里取一样东西。这个时候问题就来了: C 没有持卡,不能进去院子,而 U 又不能把卡直接给 C (卡上面有很多个人机密信息,不方便外泄哦)。怎么办呢?
哦,对了,U 可以带着 C 去门口,告诉SP:这个人是我认识的,他需要进去帮我拿我的一样东西,请予放行。这样,U 既不用将带有个人私密信息的门卡交给 C,C 也通过验证拿到了属于 U 的东西。
有的人要问了,是不是下次 C 想要再进 SP 的拿 U 的东西的话,是不是就不用 U 的指引了呢?人类社会的情况通常是这样的。可惜,在 HTTP 的世界里,由于 HTTP 是无状态的协议,因此,SP 仍然不会认识 C。所以,每次 C 想要取东西,总是需要 U 的指引。是不是很麻烦呢?呵呵。但是为了安全,麻烦一点又有什何妨!
上面介绍了 OAuth 认证的基本思路,如果你还不理解,可以参考 OAuth认证流程图, 或者查看腾讯微博关于OAuth认证的介绍。OAuth
官方网站就有一篇文档教程《OAuth入门指南》,不过没有中文版本。有兴趣同学的也可以自己看看。
OAuth 认证授权有以下几个特点:
1. 简单:不管是 OAuth 服务提供者还是应用开发者,都很容易于理解与使用;
2. 安全:没有涉及到用户密钥等信息,更安全更灵活;
3. 开放:任何服务提供商都可以实现 OAuth,任何软件开发商都可以使用 OAuth;
那么下面我们就作为服务提供商角色,来实现 OAuth 认证服务器的安装和搭建。
其实,很多先行者已经开发出了很多的 OAuth 消费方代码(客户端)和服务提供方代码(服务端),这里是它们的一些列表,其中包含了 .NET (C#/VB.NET), ColdFusion, Java, Javascript, Jifty, Objective-C, OCaml, Perl, PHP, Python,
Ruby, Erlang 和其他语言的一些实现。
通过 Google,我找到了一个开源的 OAuth 服务端代码和消费方开源代码库项目——oauth-php. 我们就借此来实现。关于OAuth,项目主页的介绍是: OAuth Consumer And Server Library For PHP. 它包含一个完整实现的可扩展的OAuth存储,支持
MySQL/MySQLi, Postgresql, PDO 和 Oracle 等多种存储方式。
它实现了以下方法:
认证进来的请求
为出去的请求签名
使用 body 为请求签名
为多用户管理消费方的 key 和 token(服务端和消费端)
记录经过类库处理的进出的请求(可以在数据库中进行可选配置)
很多网站都在使用oauth-php, 包括荷兰阿姆斯特丹Mediamatic Lab实验室出品的anyMeta CMS. 目前,oauth-php 的代码主要由Corollarium Technologies 负责维护。
为你的服务器增加 OAuth 非常简单。你需要检查进来的请求中 OAuth 认证细节。首先,我们需要四个控制器 controller 文件:
oauth_register.php 使消费方用户获得 key 和密钥
request_token.php 返回一个未认证的 request token
authorize.php 认证一个request token
access_token.php 将认证后的 request token 置换为 access token
以下的例子,假设使用的数据存储器是MySQL。你也可以使用其他数据库——当你第一次使用 OAuthStore 实例的时候指定一个参数,告诉它你要使用的数据库。
1 | $store = OAuthStore::instance('mystore'); |
1 | $store = OAuthStore::instance('MySQL'); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | if (OAuthRequestVerifier::requestIsSigned()) { try { $req = new OAuthRequestVerifier(); $user_id = $req->verify(); // 如果存在 user_id, 那么作为那个用户角色登录(对于本次请求) if ($user_id) { // **** 在这里新增你的代码 **** } } catch (OAuthException $e) { // 请求已经签名,但是认证失败 header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: OAuth realm=""'); header('Content-Type: text/plain; charset=utf8'); echo $e->getMessage(); exit(); } } |
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 | // 当前登录用户 $user_id = 1; // 下面的内容应该来自用户填写的表单 $consumer = array( // 下面两个是必须的 'requester_name' => 'John Doe', 'requester_email' => 'john@example.com', // 下面的是可选的 'callback_uri' => 'http://www.myconsumersite.com/oauth_callback', 'application_uri' => 'http://www.myconsumersite.com/', 'application_title' => 'John Doe\'s consumer site', 'application_descr' => 'Make nice graphs of all your data', 'application_notes' => 'Bladibla', 'application_type' => 'website', 'application_commercial' => 0 ); // 注册消费方 $store = OAuthStore::instance(); $key = $store->updateConsumer($consumer, $user_id); // 从数据存储器获得完整的消费方信息 $consumer = $store->getConsumer($key); // 消费方用户将需要 key 和 secret $consumer_id = $consumer['id']; $consumer_key = $consumer['consumer_key']; $consumer_secret = $consumer['consumer_secret']; |
你还可以请求一个特定用户注册的所有消费方列表:
1 2 3 4 5 6 | // 当前登录用户 $user_id = 1; // 取得这个用户注册的全部消费方列表 $store = OAuthStore::instance(); $list = $store->listConsumers($user_id); |
1 2 3 | $server = new OAuthServer(); $token = $server->requestToken(); exit(); |
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 31 32 | // 当前登录用户 $user_id = 1; // 取得OAuth存储器和OAtuh服务器对象 $store = OAuthStore::instance(); $server = new OAuthServer(); try { // 检查当前请求中是否包含合法的request token // 返回一个包含消费方key, 消费方secret, token, token secret 和 token 类型的数组. $rs = $server->authorizeVerify(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { // 检查用户是否点击了 'allow' 按钮或者其他你指定的按钮) $authorized = array_key_exists('allow', $_POST); // 设置 request token 的认证状态(已认证或者是未认证) // 当包含 oauth_callback 回调的时候,这些将传给消费方 $server->authorizeFinish($authorized, $user_id); // 没有 oauth_callback 回调, 显示认证结果 // ** 你的代码 ** } } catch (OAuthException $e) { // 没有需要认证的 request token, 显示一个可以输入 request token 的页面 // ** 你的代码 ** } |
1 2 | $server = new OAuthServer(); $server->accessToken(); |
接上一篇《一步一步搭建 OAuth 认证服务器》的文章,其实也就是介绍了一下 OAuth 的理解和 oauth-php 这个开源的项目,并没有做出一个演示。今天这篇文章就来做一个Demo,我们基于
PHP 来搭建一个 OAuth认证服务器。开始吧!
为了方便理解,可以先看一下在 OAuth 认证过程中的几个关键术语,这也是RFC5849 中 “1.1. Terminology” 小节的内容。也可以查看其中文版本。
想了一下,没有想到好的应用场景,干脆就使用 RFC5849 中的例子吧。这个例子大概的意思是:
1 2 3 4 5 | Jane (用户,资源的所有者) 将自己度假的照片 (受保护资源) 上传到了图片分享网站A (服务提供方). 她现在想要在另外一个网站B (Client, 消费方) 在线打印这些照片. 一般情况下, Jane 需要使用自己的用户名和密码登陆网站A. 但是, Jane 并不希望将自己的用户名和密码泄露给网站B. 可是网站B需要访问图片分享网站A的图片并将其打印出来. |
1 2 3 4 5 6 7 8 | # 服务提供方 Service Provider 服务提供服务器, 提供受保护资源 www.service.com # 服务提供方 Service Provider OAuth认证服务器,进行请求认证 auth.service.com # 消费方 Consumer 客户应用服务器, 用来发起认证请求 www.demo.com |
接下来,我们为网站 A 虚拟一个用户 Jane,并将其用户名和密码以及她的照片保存在 MySQL 数据库中。
先创建一个数据库,名曰:photo, 在其中新建一个表user:
1 2 3 4 5 6 7 8 | CREATE DATABASE `photo`; CREATE TABLE IF NOT EXISTS `user` ( `userId` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID', `userName` varchar(20) NOT NULL COMMENT '用户名', `password` char(32) NOT NULL COMMENT '会员密码', PRIMARY KEY (`userId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息表'AUTO_INCREMENT=1 ; |
1 2 3 4 5 6 7 | CREATE TABLE IF NOT EXISTS `image` ( `imageId` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '图片Id', `userId` int(11) unsigned NOT NULL COMMENT '用户Id', `imagePath` varchar(255) NOT NULL COMMENT '图片路径', PRIMARY KEY (`imageId`), KEY `userId` (`userId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='图片表'AUTO_INCREMENT=1 ; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | INSERTINTO`photo`.`user` ( `userId` , `userName` , `password` ) VALUES ( '1','jane', MD5('123456') ); INSERTINTO`photo`.`image` ( `imageId` , `userId` , `imagePath` ) VALUES ( NULL ,'1','path/to/jane/image.jpeg' ); |
我们这里使用的是 MySQL 数据库,打开浏览器,访问 http://auth.service.com/oauth-php/library/store/mysql/install.php 来进行数据表的安装。事先需要编辑 install.php 进行数据库配置。安装完毕,请将该文件的数据库连接部分重新注释掉。
下面来实现OAUTH服务器端的应用注册功能。
首先在 oauth.service.com 服务器下新建一个 config.inc.php 文件,文件内容如下:
1 2 3 4 5 6 7 8 9 | <?php // 数据库连接信息 $dbOptions = array( 'server' => 'localhost', 'username' => 'root', 'password' => '123456', 'database' => 'photo' ); ?> |
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 31 32 33 34 35 36 37 38 39 40 | <?php // 当前登录用户 $user_id = 1; // 来自用户表单 $consumer = array( // 下面两项必填 'requester_name' => 'Fising', 'requester_email' => 'Fising@qq.com', // 以下均为可选 'callback_uri' => 'http://www.demo.com/oauth_callback', 'application_uri' => 'http://www.demo.com/', 'application_title' => 'Online Printer', 'application_descr' => 'Online Print Your Photoes', 'application_notes' => 'Online Printer', 'application_type' => 'website', 'application_commercial' => 0 ); include_once 'config.inc.php'; include_once 'oauth-php/library/OAuthStore.php'; // 注册消费方 $store = OAuthStore::instance('MySQL', $dbOptions); $key = $store->updateConsumer($consumer, $user_id); // 获取消费方信息 $consumer = $store->getConsumer($key, $user_id); // 消费方注册后得到的 App Key 和 App Secret $consumer_id = $consumer['id']; $consumer_key = $consumer['consumer_key']; $consumer_secret = $consumer['consumer_secret']; // 输出给消费方 echo 'Your App Key: ' . $consumer_key; echo '<br />'; echo 'Your App Secret: ' . $consumer_secret; ?> |
看到的页面应该类似于:
1 2 | Your App Key: de94eb65317c0d7a00af1261fc26882c04df0f850 Your App Secret: 7769ae71e703509a92c7f3816a9268af |
接下来,消费方 www.demo.com 就可以使用这个 App Key 和 App Secret,向认证服务器请求未授权的 Request token 了。这一步需要做两件事情:① 消费方 www.demo.com 向 OAuth Server 也就是 auth.service.com 请求未授权的 Request token;② OAuth Server 处理消费方的请求,生成并将未授权的 Request token 返回给消费方;
先来实现第②件任务。
在认证服务器 auth.service.com 的根目录下新建一个文件”request_token.php”, 文件内容是:
1 2 3 4 5 6 7 8 9 10 11 | <?php include_once 'config.inc.php'; include_once 'oauth-php/library/OAuthStore.php'; include_once 'oauth-php/library/OAuthServer.php'; $store = OAuthStore::instance('MySQL', $dbOptions); $server = new OAuthServer(); $server->requestToken(); exit(); ?> |
这里要特别注意一点,如果测试的时候,消费方和服务提供方在同一台服务器,就像我现在的情况,三个服务器都在同一个虚拟机里,那么要注意,客户端请求的时候,可能发生找不到主机的问题。为啥?因为服务器找不到虚拟的 auth.service.com 认证服务器。怎么解决呢?
Windows下面,我们可以设置 hosts 主机表文件,使某一域名的指向某一固定IP地址。Linux下面也有类似的主机表文件,它的位置是 /etc/hosts,接下来如何做,这里就不用讲啦。
现在来实现第①件任务。
首先在消费方数据库服务器将认证服务器添加到消费方的 OAuthStore 中。这里的数据库安装方式与服务方相同,不再赘述。
然后,我们再消费方服务器 www.demo.com 的根目录添加一个 “config.inc.php” 文件,保存消费方自己的数据库连接信息。我这里由于使用的是虚拟主机,恰好消费方和认证服务器的数据库连接参数是一样的。实际情况可能不是这样。文件的内容与上面的类似:
1 2 3 4 5 6 7 8 9 | <?php // 数据库连接信息 $dbOptions = array( 'server' => 'localhost', 'username' => 'root', 'password' => '123456', 'database' => 'photo' ); ?> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php include_once 'config.inc.php'; include_once 'oauth-php/library/OAuthStore.php'; $store = OAuthStore::instance('MySQL', $dbOptions); // 当前用户的ID, 必须为整数 $user_id = 1; // 服务器描述信息 $server = array( 'consumer_key' => 'de94eb65317c0d7a00af1261fc26882c04df0f850', 'consumer_secret' => '7769ae71e703509a92c7f3816a9268af', 'server_uri' => 'http://auth.service.com/', 'signature_methods' => array('HMAC-SHA1', 'PLAINTEXT'), 'request_token_uri' => 'http://auth.service.com/request_token.php', 'authorize_uri' => 'http://auth.service.com/authorize.php', 'access_token_uri' => 'http://auth.service.com/access_token.php' ); // 将服务器信息保存在 OAuthStore 中 $consumer_key = $store->updateServer($server, $user_id); ?> |
有了认证服务器的相关信息,我们现在可以去获取“未认证的token”了。在 www.demo.com 根目录新建一个文件 index.php:
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 31 32 33 34 35 36 37 38 39 40 41 | <?php if(isset($_GET['req']) && ($_GET['req'] == 1)){ include_once 'config.inc.php'; include_once 'oauth-php/library/OAuthStore.php'; include_once 'oauth-php/library/OAuthRequester.php'; $store = OAuthStore::instance('MySQL', $dbOptions); // 用户Id, 必须为整型 $user_id = 1; // 消费者key $consumer_key = '286cec927c4c5482e75d80759e9fdd8904df10e2f'; // 从服务器获取未授权的token $token = OAuthRequester::requestRequestToken($consumer_key,$user_id); var_dump($token); die(); } else{ ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>测试页面</title> </head> <body> <p>消费放测试页面,点击下面的按钮开始测试</p> <input type="button" name="button" value="Click Me" id="RequestBtn"/> <script type="text/javascript"> document.getElementById('RequestBtn').onclick = function(){ window.location = 'index.php?req=1'; } </script> </body> </html> <?php } ?> |
1 | array(2) { ["authorize_uri"]=> string(37) "http://auth.service.com/authorize.php" ["token"]=> string(41) "dc8e8df797d9737b0acfe7a8b549005604df5e485" } |
接下来,根据 OAuth 验证的流程,应该是重定向用户浏览器到 auth.service.com 进行 token 授权。
在 auth.demo.com 服务器根目录新建一个文件 authorize.php, 代码如下:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <?php session_start(); if (empty($_SESSION['authorized'])) { $uri = $_SERVER['REQUEST_URI']; header('Location: /login.php?goto=' . urlencode($uri)); exit(); } include_once 'config.inc.php'; include_once 'oauth-php/library/OAuthStore.php'; include_once 'oauth-php/library/OAuthServer.php'; //登陆用户 $user_id = 1; // 取得 oauth store 和 oauth server 对象 $store = OAuthStore::instance('MySQL', $dbOptions); $server = new OAuthServer(); try { // 检查当前请求中是否包含一个合法的请求token // 返回一个数组, 包含consumer key, consumer secret, token, token secret 和 token type. $rs = $server->authorizeVerify(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { // 判断用户是否点击了 "allow" 按钮(或者你可以自定义为其他标识) $authorized = array_key_exists('allow', $_POST); // 设置token的认证状态(已经被认证或者尚未认证) // 如果存在 oauth_callback 参数, 重定向到客户(消费方)地址 $server->authorizeFinish($authorized, $user_id); // 如果没有 oauth_callback 参数, 显示认证结果 // ** 你的代码 ** } else { echo 'Error'; } } catch (OAuthException $e) { // 请求中没有包含token, 显示一个使用户可以输入token以进行验证的页面 // ** 你的代码 ** } ?> |
http://blog.163.com/da7_1@126/blog/static/10407267820119303659937/
相关文章推荐
- 【精品推荐】高质量PHP代码的50个实用技巧:非常值得收藏
- 超常用的PHP正则表达式收集整理
- 15个超实用的php正则表达式
- PHP基于yii框架实现生成ICO图标
- php邮箱地址正则表达式验证
- php正则表达式学习笔记
- 开启PHP Static 关键字之旅模式
- yii2.0 验证用户名唯一与邮箱唯一
- PHP数组操作详细解释
- 几种php 删除数组元素方法
- PHP程序猿必备的七种武器
- PHP文件函数 is_file和file_exists区别
- thinkphp框架中“关联操作”的完整定义详解
- php obstart 详解
- weiphp——关于留言板插件的创建和使用
- (转)如何检查系统是否支持Zend Optimizer
- PHP开发环境搭建详细教程
- mac上配置php开发环境
- phpStorm显示localhost:63342 和 502 Bad gateway解决方法
- phpStorm显示localhost:63342 和 502 Bad gateway解决方法