代码已push到github欢迎star: https://github.com/grasses/codeigniter-oauth2-server
0x01.About
最近在搭建Oauth2.0第三方接入开放平台,主要是使用Github开源项目服务模块https://github.com/bshaffer/oauth2-server-php和CodeIgniter结合。
一般来说做开放平台主要包括:Oauth2.0认证平台、Resource资源API平台、Open开发者注册平台,以及API说明等。
Oauth2.0测试平台已经搭建好,请访问 http://oauth2.homeway.me/oauth2/test/
0x02.About Oauth2.0
OAuth 2.0授权前,第三方应用必须到平台上进行注册,注册过程中可能需要填写的内容有:应用类型,授权成功回调地址,以及其他平台需要的资料(应用名称、网址、介绍、LOGO图片等)。
OAuth 2.0标准主要围绕三类应用:Web应用、基于客户端的应用、原生应用。
应用在Open开发者平台注册完成会得到一个应用client_id和一个client_secret,一般叫App Key
,密钥叫App Secret
,这两样东西作用跟用户名密码是一样的。
OAuth 2.0 RFC 中提到的授权方式有四种:授权码(Authorization Code)、隐式授权(Implicit Grant)、用户口令(Resource Owner Password Credentials)、应用口令(Client Credentials)。
这四种方式最终的目的都是要获得Access Token,然后通过请求Resource服务器获取资源。
0x03.Grant_type
说说每种授权方式使用到的地方,或授权的方式。
Authorization Code
授权码方式在很多地方都有用到,微博登陆,微信登陆等都是。
认证过程主要是跳转到Oauth2.0平台,认证后跳转回第三方应用平台,并通过callback的url中携带code、state、token_type等信息,然后第三方平台通过code获取到access_token,进而调用开放API获取到资源。
第三方请求过程必须附带,response_type
(回调类型:code,token),client_id
(开发者app key),redirect_uri
(回调链接),state
(防止csrf,authorization认证跳转后原样返回)。
例如:http://localhost:8085/oauth2/authorize/index?redirect_uri=http://homeway.me&response_type=code&client_id=testclient&state=ae5f8c93dc51d856d6536aec528c31c6f6450458
测试例子:http://brentertainment.com/oauth2/
第一步:跳转到Oauth2.0服务器:
认证过程中会请求scope
权限表,用户可以拒绝相应权限。
第二步:用户确认请求的权限,回调得到code:
第三步:第三方平台通过code得到access_token,然后通过API调用Resource服务器资源。
这个过程需要发送client_id
,client_secret
(App Secret),grant_type
('authorization_code'),code
,redirect_uri
给oauth2服务器获取access_token
。
例如:http://brentertainment.com/oauth2/client/request_token/authorization_code?code=bab6b7dee32f629397acbb16a4d8e50c6c3d424d
Implicit Grant
隐式授权流程(Implicit Grant)其实就是Authorization Code的一个简化版本,不是回调code,而是直接回调access_token给第三方开发者,response_type
变为token,其他和Authorization Code一样。
例如:http://brentertainment.com/oauth2/lockdin/authorize?response_type=token&client_id=demoapp&redirect_uri=http%3A%2F%2Fbrentertainment.com%2Foauth2%2Fclient%2Freceive_implicit_token&state=377edd18bd3070e4317889b0b3371c16
跳转后就得到了,如下链接:http://brentertainment.com/oauth2/client/receive_implicit_token#access_token=a845c2c81bc57613bbc5dee1fec173a3fbd0f474&expires_in=3600&token_type=Bearer&state=377edd18bd3070e4317889b0b3371c16
Client Credentials
应用授权(Client Credentials)主要用于第三方应用直接获取一些公开的数据,不需要用户跳转认证,也不需要获取用户的openid,因为都是一些公共的资源。
我的请求数据为:{client_id: "testclient", client_secret: "testpass", grant_type: "client_credentials", scope: "userinfo cloud file node"}
Oauth2给我的回调数据:{"access_token":"417206d0e162d743338c04da9f8eb72f99daff6b","expires_in":3600,"token_type":"Bearer","scope":"userinfo cloud file node"}
可以看到有了access_token,然后我就可以用access_token去找Resource服务器要资源了,这里限定了scope
权限表,表的权限在open平台注册的时候就确定下来了。
Resource Owner Password Credentials
用户口令(Resource Owner Password Credentials)适合内部应用调用使用,比如公司有两个平台,A和B,那么我就可以在Oauth2下通过Password Credentials
模式实现A应用与B应用之间通信,还可以开放内部接口。
请求的数据格式是:
`{grant_type: "password
username:"user", password: "pass",client_id: ""testclient", client_secret: "testpass", scope: "userinfo cloud file node}`
回调数据比Client Credentials多了一个refresh_token
:
`{"access_token":"8a478275f8d2d5ac767f94ef0684a1fc2883eb24",
"expires_in":3600,
"token_type":"Bearer",
"scope":"userinfo cloud file node",
"refresh_token":"69a5e7b995ed4376bd6dd58380bfe09b51137dcb"}`
那么当access_token
过期后,就可以通过refresh_token
再次激活一个新的access_token
,黑魔法,自己给自己开后门。
激活请求发送的数据为:
`{grant_type: "refresh_token",
username:"user", password: "pass", client_id: ""testclient", client_secret: "testpass", scope: "userinfo cloud file node}`
返回还是一个新的access_token数据。
0x04.CodeIgniter与Oauth2.0
四种授权方式都说过了,那么就开始搭建基于CodeIgniter的Oauth2.0平台了。
基础环境搭建
1.下载CI框架:$wget https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.0.0
2.解压 $unzip CodeIgniter-3.0.0.zip
3.进入library目录 $cd CodeIgniter-3.0.0/application/libraries
4.获取oauth2-php-server: git clone https://github.com/bshaffer/oauth2-server-php && mv -f oauth2-server-php oauth2
5.通过composer安装 oauth2-server-php :cd oauth2 && composer install
如果国内composer安装慢的话,我打了一个包,可以再这里下载到:oauth2-server-php.zip
Oauth2.0数据库
好了,ci和oauth2都处理好了,接下来导入下数据库的sql文件。
oauth2.0平台支持多种数据库,可以在oauth2/src/Oauth2/Storage/
里面看到,有mongodb、mysql、redis等。
这里就选简单的mysql吧,数据库主要包含oauth_access_tokens、oauth_authorization_codes、oauth_clients、oauth_jwt、oauth_refresh_tokens、oauth_scopes、oauth_users几个表。
oauth_users
是Password Credentials认证的时候用的表,oauth_scopes
存放权限表,oauth_refresh_tokens
是Password Credentials认证的时候的refresh_token表,oauth_clients
存放开发者注册的信息表。
sql文件可以在这里下载:http://homeway.me/code/oauth2.sql
Server服务
接下来在CodeIgniter-3.0.0/application/libraries/oauth2
里面新建一个server.php
,
用于对oauth2内调用与对外ci服务的接口。
创建一个Authorization Code服务
class Server{
function __construct(){
OAuth2\Autoloader::register();
$this->storage = new OAuth2\Storage\Pdo(array('dsn' => 'mysql:dbname=oauth;host=localhost', 'username' => '', 'password' => ''));
$this->server = new OAuth2\Server($this->storage, array('allow_implicit' => true));
$this->request = OAuth2\Request::createFromGlobals();
$this->response = new OAuth2\Response();
}
public function authorize($is_authorized){
$this->server->addGrantType(new OAuth2\GrantType\AuthorizationCode($this->storage));
$this->server->handleAuthorizeRequest($this->request, $this->response, $is_authorized);
if ($is_authorized) {
$code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40);
header("Location: ".$response->getHttpHeader('Location'));
}
$response->send();
}
}
创建一个Password Credentials服务
class Server{
function __construct(){
OAuth2\Autoloader::register();
$this->storage = new OAuth2\Storage\Pdo(array('dsn' => 'mysql:dbname=oauth;host=localhost', 'username' => '', 'password' => ''));
$this->server = new OAuth2\Server($this->storage, array('allow_implicit' => true));
$this->request = OAuth2\Request::createFromGlobals();
$this->response = new OAuth2\Response();
}
public function password_credentials(){
$users = array("user" => array("password" => 'pass', 'first_name' => 'homeway', 'last_name' => 'yao'));
$storage = new OAuth2\Storage\Memory(array('user_credentials' => $users));//user是认证的账户,在表oauth_users中
$this->server->addGrantType(new OAuth2\GrantType\UserCredentials($storage));
$this->server->handleTokenRequest($this->request)->send();
}
}
创建一个Client Credentials服务
class Server{
function __construct(){
OAuth2\Autoloader::register();
$this->storage = new OAuth2\Storage\Pdo(array('dsn' => 'mysql:dbname=oauth;host=localhost', 'username' => '', 'password' => ''));
$this->server = new OAuth2\Server($this->storage, array('allow_implicit' => true));
$this->request = OAuth2\Request::createFromGlobals();
$this->response = new OAuth2\Response();
}
public function client_credentials(){
$this->server->addGrantType(new OAuth2\GrantType\ClientCredentials($this->storage, array("allow_credentials_in_request_body" => true)));
$this->server->handleTokenRequest($this->request)->send();
}
}
创建一个refresh_token服务
class Server{
function __construct(){
OAuth2\Autoloader::register();
$this->storage = new OAuth2\Storage\Pdo(array('dsn' => 'mysql:dbname=oauth;host=localhost', 'username' => '', 'password' => ''));
$this->server = new OAuth2\Server($this->storage, array('allow_implicit' => true));
$this->request = OAuth2\Request::createFromGlobals();
$this->response = new OAuth2\Response();
}
public function refresh_token(){
$this->server->addGrantType(new OAuth2\GrantType\RefreshToken($this->storage, array(
"always_issue_new_refresh_token" => true,
"unset_refresh_token_after_use" => true,
"refresh_token_lifetime" => 2419200,
)));
$this->server->handleTokenRequest($this->request)->send();
}
}
0x04.About Package
篇幅太大了,我觉定,把代码打包下来,好了。^.().^
http://785igi.com1.z0.glb.clouddn.com/share/build-oauth2-under-codeigniter.zip
下面是打包好的测试平台你也可以通过http://oauth2.homeway.me/oauth/test/来进入测试平台。
平台web访问路径为:/oauth/test/
、/oauth2/RefreshToken
,/oauth2/resource
,/oauth2/authorize/token
,/oauth2/PasswordCredentials
,/oauth2/ClientCredentials
,你也可以从相应的源码中读到这些地址。
参考:
1.http://tools.ietf.org/html/rfc6749
2.http://brentertainment.com/oauth2/
3.oauth2-server-php-docs
4.新浪oauth2授权机制说明
5.腾讯OAuth2.0简介
6.腾讯API调试平台
本文出自 夏日小草,转载请注明出处:http://homeway.me/2015/06/29/build-oauth2-under-codeigniter/
-by小草
2015-06-29 02:04:10
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。