Исправлено поведение User\Component::getIdentity(), если в контроллере не было accessFilter

This commit is contained in:
ErickSkrauch 2016-12-11 17:58:08 +03:00
parent 9fe42e4623
commit b00c4ae4fc
2 changed files with 89 additions and 33 deletions

View File

@ -23,7 +23,7 @@ use yii\web\User as YiiUserComponent;
* @property AccountSession|null $activeSession * @property AccountSession|null $activeSession
* @property AccountIdentity|null $identity * @property AccountIdentity|null $identity
* *
* @method AccountIdentity|null getIdentity($autoRenew = true) * @method AccountIdentity|null loginByAccessToken($token, $type = null)
*/ */
class Component extends YiiUserComponent { class Component extends YiiUserComponent {
@ -39,6 +39,8 @@ class Component extends YiiUserComponent {
public $sessionTimeout = 'P7D'; public $sessionTimeout = 'P7D';
private $_identity;
public function init() { public function init() {
parent::init(); parent::init();
if (!$this->secret) { if (!$this->secret) {
@ -46,6 +48,24 @@ class Component extends YiiUserComponent {
} }
} }
/**
* @param bool $autoRenew
* @return null|AccountIdentity
*/
public function getIdentity($autoRenew = true) {
$result = parent::getIdentity($autoRenew);
if ($result === null && $this->_identity !== false) {
$bearer = $this->getBearerToken();
if ($bearer !== null) {
$result = $this->loginByAccessToken($bearer);
}
$this->_identity = $result ?: false;
}
return $result;
}
/** /**
* @param IdentityInterface $identity * @param IdentityInterface $identity
* @param bool $rememberMe * @param bool $rememberMe
@ -149,14 +169,9 @@ class Component extends YiiUserComponent {
return null; return null;
} }
$authHeader = Yii::$app->request->getHeaders()->get('Authorization'); $bearer = $this->getBearerToken();
if ($authHeader === null || !preg_match('/^Bearer\s+(.*?)$/', $authHeader, $matches)) {
return null;
}
$token = $matches[1];
try { try {
$token = $this->parseToken($token); $token = $this->parseToken($bearer);
} catch (VerificationException $e) { } catch (VerificationException $e) {
return null; return null;
} }
@ -203,4 +218,16 @@ class Component extends YiiUserComponent {
]; ];
} }
/**
* @return ?string
*/
private function getBearerToken() {
$authHeader = Yii::$app->request->getHeaders()->get('Authorization');
if ($authHeader === null || !preg_match('/^Bearer\s+(.*?)$/', $authHeader, $matches)) {
return null;
}
return $matches[1];
}
} }

View File

@ -16,7 +16,6 @@ use tests\codeception\common\_support\ProtectedCaller;
use tests\codeception\common\fixtures\AccountFixture; use tests\codeception\common\fixtures\AccountFixture;
use tests\codeception\common\fixtures\AccountSessionFixture; use tests\codeception\common\fixtures\AccountSessionFixture;
use Yii; use Yii;
use yii\web\HeaderCollection;
use yii\web\Request; use yii\web\Request;
class ComponentTest extends TestCase { class ComponentTest extends TestCase {
@ -24,7 +23,7 @@ class ComponentTest extends TestCase {
use ProtectedCaller; use ProtectedCaller;
/** /**
* @var Component * @var Component|\PHPUnit_Framework_MockObject_MockObject
*/ */
private $component; private $component;
@ -40,6 +39,46 @@ class ComponentTest extends TestCase {
]; ];
} }
public function testGetIdentity() {
$this->specify('getIdentity should return null, if not authorization header', function() {
$this->mockAuthorizationHeader(null);
$this->assertNull($this->component->getIdentity());
});
$this->specify('getIdentity should return null, if passed bearer token don\'t return any account', function() {
$this->mockAuthorizationHeader('some-auth');
/** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
$component = $this->getMockBuilder(Component::class)
->setMethods(['loginByAccessToken'])
->setConstructorArgs([$this->getComponentArguments()])
->getMock();
$component
->expects($this->once())
->method('loginByAccessToken')
->willReturn(null);
$this->assertNull($component->getIdentity());
});
$this->specify('getIdentity should return identity from loginByAccessToken method', function() {
$identity = new AccountIdentity();
$this->mockAuthorizationHeader('some-auth');
/** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
$component = $this->getMockBuilder(Component::class)
->setMethods(['loginByAccessToken'])
->setConstructorArgs([$this->getComponentArguments()])
->getMock();
$component
->expects($this->once())
->method('loginByAccessToken')
->willReturn($identity);
$this->assertEquals($identity, $component->getIdentity());
});
}
public function testLogin() { public function testLogin() {
$this->mockRequest(); $this->mockRequest();
$this->specify('success get LoginResult object without session value', function() { $this->specify('success get LoginResult object without session value', function() {
@ -117,30 +156,9 @@ class ComponentTest extends TestCase {
$component $component
->expects($this->any()) ->expects($this->any())
->method('getIsGuest') ->method('getIsGuest')
->will($this->returnValue(false)); ->willReturn(false);
/** @var HeaderCollection|\PHPUnit_Framework_MockObject_MockObject $headersCollection */ $this->mockAuthorizationHeader($result->getJwt());
$headersCollection = $this->getMockBuilder(HeaderCollection::class)
->setMethods(['get'])
->getMock();
$headersCollection
->expects($this->any())
->method('get')
->with($this->equalTo('Authorization'))
->will($this->returnValue('Bearer ' . $result->getJwt()));
/** @var Request|\PHPUnit_Framework_MockObject_MockObject $request */
$request = $this->getMockBuilder(Request::class)
->setMethods(['getHeaders'])
->getMock();
$request
->expects($this->any())
->method('getHeaders')
->will($this->returnValue($headersCollection));
Yii::$app->set('request', $request);
$session = $component->getActiveSession(); $session = $component->getActiveSession();
expect($session)->isInstanceOf(AccountSession::class); expect($session)->isInstanceOf(AccountSession::class);
@ -203,6 +221,17 @@ class ComponentTest extends TestCase {
return $request; return $request;
} }
/**
* @param string $bearerToken
*/
private function mockAuthorizationHeader($bearerToken = null) {
if ($bearerToken !== null) {
$bearerToken = 'Bearer ' . $bearerToken;
}
Yii::$app->request->headers->set('Authorization', $bearerToken);
}
private function getComponentArguments() { private function getComponentArguments() {
return [ return [
'identityClass' => AccountIdentity::class, 'identityClass' => AccountIdentity::class,