Skip to content

Commit c7f3c05

Browse files
committed
Oauth2 server wrapper
1 parent fe61813 commit c7f3c05

12 files changed

+663
-38
lines changed

Module.php

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace filsh\yii2\oauth2server;
4+
5+
use \Yii;
6+
7+
class Module extends \yii\base\Module
8+
{
9+
public $options = [];
10+
11+
public $storageMap = [];
12+
13+
public $storageDefault = 'filsh\yii2\oauth2server\storage\Pdo';
14+
15+
private $_server;
16+
17+
public function getServer($force = false)
18+
{
19+
if($this->_server === null || $force === true) {
20+
$storages = $this->createStorage();
21+
$server = new \OAuth2\Server($storages, $this->options);
22+
23+
$server->addGrantType(new \OAuth2\GrantType\UserCredentials($storages['user_credentials']));
24+
25+
$this->_server = $server;
26+
}
27+
return $this->_server;
28+
}
29+
30+
public function getRequest()
31+
{
32+
return \OAuth2\Request::createFromGlobals();
33+
}
34+
35+
public function getResponse()
36+
{
37+
return new \OAuth2\Response();
38+
}
39+
40+
protected function createStorage()
41+
{
42+
$connection = Yii::$app->getDb();
43+
if(!$connection->getIsActive()) {
44+
$connection->open();
45+
}
46+
47+
$storages = [];
48+
foreach($this->storageMap as $name => $storage) {
49+
$storages[$name] = Yii::createObject($storage);
50+
}
51+
52+
$defaults = [
53+
'access_token',
54+
'authorization_code',
55+
'client_credentials',
56+
'client',
57+
'refresh_token',
58+
'user_credentials',
59+
'public_key',
60+
'jwt_bearer',
61+
'scope',
62+
];
63+
foreach($defaults as $name) {
64+
if(!isset($storages[$name])) {
65+
$storages[$name] = Yii::createObject($this->storageDefault);
66+
}
67+
}
68+
69+
return $storages;
70+
}
71+
}

Server.php

-38
This file was deleted.

controllers/DefaultController.php

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace filsh\yii2\oauth2server\controllers;
4+
5+
use \Yii;
6+
use yii\helpers\ArrayHelper;
7+
use yii\filters\auth\CompositeAuth;
8+
use yii\filters\auth\HttpBearerAuth;
9+
10+
use filsh\yii2\oauth2server\filters\ExceptionFilter;
11+
use filsh\yii2\oauth2server\filters\auth\QueryParamAuth;
12+
13+
class DefaultController extends \yii\rest\Controller
14+
{
15+
/**
16+
* @inheritdoc
17+
*/
18+
public function behaviors()
19+
{
20+
return ArrayHelper::merge(parent::behaviors(), [
21+
'authenticator' => [
22+
'class' => CompositeAuth::className(),
23+
'authMethods' => [
24+
HttpBearerAuth::className(),
25+
QueryParamAuth::className(),
26+
],
27+
'except' => ['token']
28+
],
29+
'exceptionFilter' => [
30+
'class' => ExceptionFilter::className()
31+
],
32+
]);
33+
}
34+
35+
public function actionToken()
36+
{
37+
$server = Yii::$app->getModule('oauth2')->getServer();
38+
$request = Yii::$app->getModule('oauth2')->getRequest();
39+
$response = $server->handleTokenRequest($request);
40+
41+
return $response->getParameters();
42+
}
43+
44+
public function actionResource()
45+
{
46+
$server = Yii::$app->getModule('oauth2')->getServer();
47+
$request = Yii::$app->getModule('oauth2')->getRequest();
48+
49+
if (!$server->verifyResourceRequest($request)) {
50+
return $server->getResponse()->getParameters();
51+
}
52+
53+
return ['success' => true, 'message' => 'You accessed my APIs!'];
54+
}
55+
}

filters/ExceptionFilter.php

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace filsh\yii2\oauth2server\filters;
4+
5+
use Yii;
6+
use yii\base\Controller;
7+
8+
class ExceptionFilter extends yii\base\Behavior
9+
{
10+
public function events()
11+
{
12+
return [Controller::EVENT_AFTER_ACTION => 'afterAction'];
13+
}
14+
15+
/**
16+
* @param ActionEvent $event
17+
* @return boolean
18+
* @throws HttpException when the request method is not allowed.
19+
*/
20+
public function afterAction($event)
21+
{
22+
$response = Yii::$app->getModule('oauth2')->getServer()->getResponse();
23+
if($response !== null && !$response->isSuccessful()) {
24+
$status = $response->getStatusCode();
25+
// TODO: необходимо также пробрасывать error_uri
26+
$message = $response->getParameter('error_description');
27+
if($message === null) {
28+
$message = P::t('yii', 'An internal server error occurred.');
29+
}
30+
throw new \yii\web\HttpException($status, $message);
31+
}
32+
}
33+
}

filters/auth/QueryParamAuth.php

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace filsh\yii2\oauth2server\filters\auth;
4+
5+
use \Yii;
6+
7+
class QueryParamAuth extends \yii\filters\auth\QueryParamAuth
8+
{
9+
/**
10+
* @inheritdoc
11+
*/
12+
public $tokenParam = 'access_token';
13+
14+
/**
15+
* @inheritdoc
16+
*/
17+
public function authenticate($user, $request, $response)
18+
{
19+
$oauthsServer = Yii::$app->getModule('oauth2')->getServer();
20+
$oauthRequest = Yii::$app->getModule('oauth2')->getRequest();
21+
if (!$oauthsServer->verifyResourceRequest($oauthRequest)) {
22+
$this->handleFailure($response);
23+
} else {
24+
return parent::authenticate($user, $request, $response);
25+
}
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
use yii\db\Schema;
4+
5+
class m140501_075311_add_oauth2_server extends \yii\db\Migration
6+
{
7+
public function up()
8+
{
9+
$tableOptions = null;
10+
if ($this->db->driverName === 'mysql') {
11+
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB';
12+
}
13+
14+
$transaction = $this->db->beginTransaction();
15+
try {
16+
$this->createTable('{{%oauth_clients}}', [
17+
'client_id' => Schema::TYPE_STRING . '(32) NOT NULL',
18+
'client_secret' => Schema::TYPE_STRING . '(32) NOT NULL',
19+
'redirect_uri' => Schema::TYPE_STRING . '(1000) NOT NULL',
20+
'grant_types' => Schema::TYPE_STRING . '(100) NOT NULL',
21+
'scope' => Schema::TYPE_STRING . '(2000) DEFAULT NULL',
22+
'user_id' => Schema::TYPE_INTEGER . ' DEFAULT NULL',
23+
'PRIMARY KEY (`client_id`)'
24+
], $tableOptions);
25+
26+
$this->createTable('{{%oauth_access_tokens}}', [
27+
'access_token' => Schema::TYPE_STRING . '(40) NOT NULL',
28+
'client_id' => Schema::TYPE_STRING . '(32) NOT NULL',
29+
'user_id' => Schema::TYPE_INTEGER . ' DEFAULT NULL',
30+
'expires' => Schema::TYPE_TIMESTAMP . ' NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
31+
'scope' => Schema::TYPE_STRING . '(2000) DEFAULT NULL',
32+
'PRIMARY KEY (`access_token`)',
33+
'FOREIGN KEY (`client_id`) REFERENCES {{%oauth_clients}} (`client_id`) ON DELETE CASCADE ON UPDATE CASCADE',
34+
], $tableOptions);
35+
36+
$this->createTable('{{%oauth_refresh_tokens}}', [
37+
'refresh_token' => Schema::TYPE_STRING . '(40) NOT NULL',
38+
'client_id' => Schema::TYPE_STRING . '(32) NOT NULL',
39+
'user_id' => Schema::TYPE_INTEGER . ' DEFAULT NULL',
40+
'expires' => Schema::TYPE_TIMESTAMP . ' NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
41+
'scope' => Schema::TYPE_STRING . '(2000) DEFAULT NULL',
42+
'PRIMARY KEY (`refresh_token`)',
43+
'FOREIGN KEY (`client_id`) REFERENCES {{%oauth_clients}} (`client_id`) ON DELETE CASCADE ON UPDATE CASCADE',
44+
], $tableOptions);
45+
46+
$this->createTable('{{%oauth_authorization_codes}}', [
47+
'authorization_code' => Schema::TYPE_STRING . '(40) NOT NULL',
48+
'client_id' => Schema::TYPE_STRING . '(32) NOT NULL',
49+
'user_id' => Schema::TYPE_INTEGER . ' DEFAULT NULL',
50+
'redirect_uri' => Schema::TYPE_STRING . '(1000) NOT NULL',
51+
'expires' => Schema::TYPE_TIMESTAMP . ' NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
52+
'scope' => Schema::TYPE_STRING . '(2000) DEFAULT NULL',
53+
'PRIMARY KEY (`authorization_code`)',
54+
'FOREIGN KEY (`client_id`) REFERENCES {{%oauth_clients}} (`client_id`) ON DELETE CASCADE ON UPDATE CASCADE',
55+
], $tableOptions);
56+
57+
$this->createTable('{{%oauth_scopes}}', [
58+
'scope' => Schema::TYPE_STRING . '(2000) NOT NULL',
59+
'is_default' => Schema::TYPE_BOOLEAN . ' NOT NULL',
60+
], $tableOptions);
61+
62+
$this->createTable('{{%oauth_jwt}}', [
63+
'client_id' => Schema::TYPE_STRING . '(32) NOT NULL',
64+
'subject' => Schema::TYPE_STRING . '(80) DEFAULT NULL',
65+
'public_key' => Schema::TYPE_STRING . '(2000) DEFAULT NULL',
66+
'PRIMARY KEY (`client_id`)',
67+
], $tableOptions);
68+
69+
$this->createTable('{{%oauth_users}}', [
70+
'username' => Schema::TYPE_STRING . '(255) NOT NULL',
71+
'password' => Schema::TYPE_STRING . '(2000) DEFAULT NULL',
72+
'first_name' => Schema::TYPE_STRING . '(255) DEFAULT NULL',
73+
'last_name' => Schema::TYPE_STRING . '(255) DEFAULT NULL',
74+
'PRIMARY KEY (`username`)',
75+
], $tableOptions);
76+
77+
// insert client data
78+
$this->batchInsert('{{%oauth_clients}}', ['client_id', 'client_secret', 'redirect_uri', 'grant_types'], [
79+
['testclient', 'testpass', 'http://fake/', 'client_credentials password'],
80+
]);
81+
82+
$transaction->commit();
83+
} catch (Exception $e) {
84+
echo 'Exception: ' . $e->getMessage() . '\n';
85+
$transaction->rollback();
86+
87+
return false;
88+
}
89+
90+
return true;
91+
}
92+
93+
public function down()
94+
{
95+
$transaction = $this->db->beginTransaction();
96+
try {
97+
$this->dropTable('{{%oauth_users}}');
98+
$this->dropTable('{{%oauth_jwt}}');
99+
$this->dropTable('{{%oauth_scopes}}');
100+
$this->dropTable('{{%oauth_authorization_codes}}');
101+
$this->dropTable('{{%oauth_refresh_tokens}}');
102+
$this->dropTable('{{%oauth_access_tokens}}');
103+
$this->dropTable('{{%oauth_clients}}');
104+
105+
$transaction->commit();
106+
} catch (Exception $e) {
107+
$transaction->rollback();
108+
echo $e->getMessage();
109+
echo "\n";
110+
echo get_called_class() . ' cannot be reverted.';
111+
echo "\n";
112+
113+
return false;
114+
}
115+
116+
return true;
117+
}
118+
}

0 commit comments

Comments
 (0)