LoginTokenService.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. namespace App\Services\Login;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Illuminate\Database\Query\Builder;
  5. use Illuminate\Support\Facades\DB;
  6. use Illuminate\Support\Facades\Request;
  7. use Illuminate\Support\Str;
  8. use Laravel\Sanctum\PersonalAccessToken;
  9. use phpDocumentor\Reflection\Types\Boolean;
  10. class LoginTokenService
  11. {
  12. protected string $table = '';
  13. protected int $expireTime = 3 * 24 * 3600; // 有效期为0 则为永久有效
  14. public function __construct($userTable)
  15. {
  16. $this->table = $userTable;
  17. }
  18. /**
  19. * 同一个用户设备 只允许在线一个
  20. *
  21. * @param int $userId
  22. * @param string $deviceName
  23. * @return string
  24. */
  25. public function createOnlyOneToken(int $userId, string $deviceName): string
  26. {
  27. $isExist = DB::table($this->table)
  28. ->select('id')
  29. ->where('user_id', $userId)
  30. ->where('name', $deviceName)->first();
  31. if ($isExist) {
  32. // 更新登录信息
  33. return $this->updateToken($isExist->id);
  34. } else {
  35. return $this->createToken($userId, $deviceName);
  36. }
  37. }
  38. /**
  39. * 创建token
  40. *
  41. * @param int $userId
  42. * @param string $deviceName
  43. * @return string
  44. */
  45. public function createToken(int $userId, string $deviceName): string
  46. {
  47. $id = DB::table($this->table)->insertGetId([
  48. 'mid' => Str::random(12),
  49. 'user_id' => $userId,
  50. 'name' => $deviceName,
  51. 'token' => hash('sha256', $plainTextToken = Str::random(40)),
  52. 'created_at' => time(),
  53. 'updated_at' => time()
  54. ]);
  55. return base64_encode($id) . '|' . $plainTextToken;
  56. }
  57. /**
  58. * @param int $id
  59. * @return string
  60. */
  61. private function updateToken(int $id): string
  62. {
  63. DB::table($this->table)->where(['id' => $id])->update([
  64. 'token' => hash('sha256', $plainTextToken = Str::random(40)),
  65. 'updated_at' => time()
  66. ]);
  67. return base64_encode($id) . '|' . $plainTextToken;
  68. }
  69. /**
  70. * 判断是否已经登录
  71. *
  72. * @return Model|Builder|mixed|object|void|null
  73. */
  74. public function checkLogin()
  75. {
  76. return $this->findToken($this->getToken());
  77. }
  78. /**
  79. * Find the token instance matching the given token.
  80. *
  81. * @param string|null $token
  82. * @return Model|Builder|mixed|object|void|null
  83. */
  84. public function findToken(?string $token)
  85. {
  86. if (empty($token)) {
  87. return null;
  88. }
  89. if (!str_contains($token, '|')) {
  90. return DB::table($this->table)->where('token', hash('sha256', $token))->first();
  91. }
  92. [$id, $token] = explode('|', $token, 2);
  93. $id = base64_decode($id);
  94. if ($instance = DB::table($this->table)->find($id)) {
  95. return hash_equals($instance->token, hash('sha256', $token)) ? $instance : null;
  96. }
  97. }
  98. /**
  99. * 撤销当前令牌
  100. *
  101. * @return bool
  102. */
  103. public function destroyCurrentAccessToken(): bool
  104. {
  105. $token = $this->getToken();
  106. if (!str_contains($token, '|')) {
  107. return DB::table($this->table)->where('token', hash('sha256', $token))->delete();
  108. }
  109. [$id, $token] = explode('|', $token, 2);
  110. return DB::table($this->table)->where('token', hash('sha256', $token))->delete();
  111. }
  112. /**
  113. * 获取登录的token
  114. *
  115. * @return string|null
  116. */
  117. public function getToken(): ?string
  118. {
  119. $token = Request::header('Authorization');
  120. if (empty($token)) {
  121. // 兼容老版本 2022-7-28
  122. $token = Request::header('x-token');
  123. }
  124. // 允许从cookie中获取
  125. if (empty($token)) {
  126. $token = $_COOKIE['officialToken'] ?? '';
  127. }
  128. return $token;
  129. }
  130. }