Token.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <?php
  2. /**
  3. * This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
  4. *
  5. * @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
  6. */
  7. namespace Lcobucci\JWT;
  8. use BadMethodCallException;
  9. use DateTime;
  10. use Generator;
  11. use Lcobucci\JWT\Claim\Validatable;
  12. use OutOfBoundsException;
  13. /**
  14. * Basic structure of the JWT
  15. *
  16. * @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
  17. * @since 0.1.0
  18. */
  19. class Token
  20. {
  21. /**
  22. * The token headers
  23. *
  24. * @var array
  25. */
  26. private $headers;
  27. /**
  28. * The token claim set
  29. *
  30. * @var array
  31. */
  32. private $claims;
  33. /**
  34. * The token signature
  35. *
  36. * @var Signature
  37. */
  38. private $signature;
  39. /**
  40. * The encoded data
  41. *
  42. * @var array
  43. */
  44. private $payload;
  45. /**
  46. * Initializes the object
  47. *
  48. * @param array $headers
  49. * @param array $claims
  50. * @param array $payload
  51. * @param Signature $signature
  52. */
  53. public function __construct(
  54. array $headers = ['alg' => 'none'],
  55. array $claims = [],
  56. Signature $signature = null,
  57. array $payload = ['', '']
  58. ) {
  59. $this->headers = $headers;
  60. $this->claims = $claims;
  61. $this->signature = $signature;
  62. $this->payload = $payload;
  63. }
  64. /**
  65. * Returns the token headers
  66. *
  67. * @return array
  68. */
  69. public function getHeaders()
  70. {
  71. return $this->headers;
  72. }
  73. /**
  74. * Returns if the header is configured
  75. *
  76. * @param string $name
  77. *
  78. * @return boolean
  79. */
  80. public function hasHeader($name)
  81. {
  82. return array_key_exists($name, $this->headers);
  83. }
  84. /**
  85. * Returns the value of a token header
  86. *
  87. * @param string $name
  88. * @param mixed $default
  89. *
  90. * @return mixed
  91. *
  92. * @throws OutOfBoundsException
  93. */
  94. public function getHeader($name, $default = null)
  95. {
  96. if ($this->hasHeader($name)) {
  97. return $this->getHeaderValue($name);
  98. }
  99. if ($default === null) {
  100. throw new OutOfBoundsException('Requested header is not configured');
  101. }
  102. return $default;
  103. }
  104. /**
  105. * Returns the value stored in header
  106. *
  107. * @param string $name
  108. *
  109. * @return mixed
  110. */
  111. private function getHeaderValue($name)
  112. {
  113. $header = $this->headers[$name];
  114. if ($header instanceof Claim) {
  115. return $header->getValue();
  116. }
  117. return $header;
  118. }
  119. /**
  120. * Returns the token claim set
  121. *
  122. * @return array
  123. */
  124. public function getClaims()
  125. {
  126. return $this->claims;
  127. }
  128. /**
  129. * Returns if the claim is configured
  130. *
  131. * @param string $name
  132. *
  133. * @return boolean
  134. */
  135. public function hasClaim($name)
  136. {
  137. return array_key_exists($name, $this->claims);
  138. }
  139. /**
  140. * Returns the value of a token claim
  141. *
  142. * @param string $name
  143. * @param mixed $default
  144. *
  145. * @return mixed
  146. *
  147. * @throws OutOfBoundsException
  148. */
  149. public function getClaim($name, $default = null)
  150. {
  151. if ($this->hasClaim($name)) {
  152. return $this->claims[$name]->getValue();
  153. }
  154. if ($default === null) {
  155. throw new OutOfBoundsException('Requested claim is not configured');
  156. }
  157. return $default;
  158. }
  159. /**
  160. * Verify if the key matches with the one that created the signature
  161. *
  162. * @param Signer $signer
  163. * @param string $key
  164. *
  165. * @return boolean
  166. *
  167. * @throws BadMethodCallException When token is not signed
  168. */
  169. public function verify(Signer $signer, $key)
  170. {
  171. if ($this->signature === null) {
  172. throw new BadMethodCallException('This token is not signed');
  173. }
  174. if ($this->headers['alg'] !== $signer->getAlgorithmId()) {
  175. return false;
  176. }
  177. return $this->signature->verify($signer, $this->getPayload(), $key);
  178. }
  179. /**
  180. * Validates if the token is valid
  181. *
  182. * @param ValidationData $data
  183. *
  184. * @return boolean
  185. */
  186. public function validate(ValidationData $data)
  187. {
  188. foreach ($this->getValidatableClaims() as $claim) {
  189. if (!$claim->validate($data)) {
  190. return false;
  191. }
  192. }
  193. return true;
  194. }
  195. /**
  196. * Determine if the token is expired.
  197. *
  198. * @param DateTime $now Defaults to the current time.
  199. *
  200. * @return bool
  201. */
  202. public function isExpired(DateTime $now = null)
  203. {
  204. $exp = $this->getClaim('exp', false);
  205. if ($exp === false) {
  206. return false;
  207. }
  208. $now = $now ?: new DateTime();
  209. $expiresAt = new DateTime();
  210. $expiresAt->setTimestamp($exp);
  211. return $now > $expiresAt;
  212. }
  213. /**
  214. * Yields the validatable claims
  215. *
  216. * @return Generator
  217. */
  218. private function getValidatableClaims()
  219. {
  220. foreach ($this->claims as $claim) {
  221. if ($claim instanceof Validatable) {
  222. yield $claim;
  223. }
  224. }
  225. }
  226. /**
  227. * Returns the token payload
  228. *
  229. * @return string
  230. */
  231. public function getPayload()
  232. {
  233. return $this->payload[0] . '.' . $this->payload[1];
  234. }
  235. /**
  236. * Returns an encoded representation of the token
  237. *
  238. * @return string
  239. */
  240. public function __toString()
  241. {
  242. $data = implode('.', $this->payload);
  243. if ($this->signature === null) {
  244. $data .= '.';
  245. }
  246. return $data;
  247. }
  248. }