JwtHttpBearerAuth.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <?php
  2. namespace sizeg\jwt;
  3. use yii\di\Instance;
  4. use yii\filters\auth\AuthMethod;
  5. /**
  6. * JwtHttpBearerAuth is an action filter that supports the authentication method based on JSON Web Token.
  7. *
  8. * You may use JwtHttpBearerAuth by attaching it as a behavior to a controller or module, like the following:
  9. *
  10. * ```php
  11. * public function behaviors()
  12. * {
  13. * return [
  14. * 'bearerAuth' => [
  15. * 'class' => \sizeg\jwt\JwtHttpBearerAuth::className(),
  16. * ],
  17. * ];
  18. * }
  19. * ```
  20. *
  21. * @author Dmitriy Demin <sizemail@gmail.com>
  22. * @since 1.0.0-a
  23. */
  24. class JwtHttpBearerAuth extends AuthMethod
  25. {
  26. /**
  27. * @var Jwt|string|array the [[Jwt]] object or the application component ID of the [[Jwt]].
  28. */
  29. public $jwt = 'jwt';
  30. /**
  31. * @var string A "realm" attribute MAY be included to indicate the scope
  32. * of protection in the manner described in HTTP/1.1 [RFC2617]. The "realm"
  33. * attribute MUST NOT appear more than once.
  34. */
  35. public $realm = 'api';
  36. /**
  37. * @var string Authorization header schema, default 'Bearer'
  38. */
  39. public $schema = 'Bearer';
  40. /**
  41. * @var callable a PHP callable that will authenticate the user with the JWT payload information
  42. *
  43. * ```php
  44. * function ($token, $authMethod) {
  45. * return \app\models\User::findOne($token->getClaim('id'));
  46. * }
  47. * ```
  48. *
  49. * If this property is not set, the username information will be considered as an access token
  50. * while the password information will be ignored. The [[\yii\web\User::loginByAccessToken()]]
  51. * method will be called to authenticate and login the user.
  52. */
  53. public $auth;
  54. /**
  55. * @inheritdoc
  56. */
  57. public function init()
  58. {
  59. parent::init();
  60. $this->jwt = Instance::ensure($this->jwt, Jwt::className());
  61. }
  62. /**
  63. * @inheritdoc
  64. */
  65. public function authenticate($user, $request, $response)
  66. {
  67. $authHeader = $request->getHeaders()->get('Authorization');
  68. if ($authHeader !== null && preg_match('/^' . $this->schema . '\s+(.*?)$/', $authHeader, $matches)) {
  69. $token = $this->loadToken($matches[1]);
  70. if ($token === null) {
  71. return null;
  72. }
  73. if ($this->auth) {
  74. $identity = call_user_func($this->auth, $token, get_class($this));
  75. } else {
  76. $identity = $user->loginByAccessToken($token, get_class($this));
  77. }
  78. return $identity;
  79. }
  80. return null;
  81. }
  82. /**
  83. * @inheritdoc
  84. */
  85. public function challenge($response)
  86. {
  87. $response->getHeaders()->set(
  88. 'WWW-Authenticate',
  89. "{$this->schema} realm=\"{$this->realm}\", error=\"invalid_token\", error_description=\"The access token invalid or expired\""
  90. );
  91. }
  92. /**
  93. * Parses the JWT and returns a token class
  94. * @param string $token JWT
  95. * @return Token|null
  96. */
  97. public function loadToken($token)
  98. {
  99. return $this->jwt->loadToken($token);
  100. }
  101. }