AuthService.php 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. <?php
  2. declare(strict_types=1);
  3. namespace app\miniapi\service;
  4. use app\miniapi\auth\Principal;
  5. use app\miniapi\auth\WechatIdentityProvider;
  6. use app\miniapi\auth\IdentityProvider;
  7. use app\miniapi\model\MiniUser;
  8. use app\miniapi\model\MiniSession;
  9. use app\miniapi\http\Fields;
  10. use app\miniapi\exception\ApiException;
  11. final class AuthService
  12. {
  13. public function __construct(private readonly IdentityProvider $provider = new WechatIdentityProvider())
  14. {
  15. }
  16. public function login(array $input): array
  17. {
  18. Fields::only($input, ['code']);
  19. $identity = $this->provider->exchange(Fields::text($input, 'code', 512));
  20. return $this->issue($identity);
  21. }
  22. /** Internal only. The HTTP controller never accepts provider identity from clients. */
  23. public function issue(array $identity): array
  24. {
  25. return (new MiniUser())->getConnection()->transaction(function () use ($identity) {
  26. $now = date('Y-m-d H:i:s');
  27. MiniUser::query()->insertOrIgnore($identity + [
  28. 'nickname' => '',
  29. 'status' => 1,
  30. 'created_at' => $now,
  31. 'updated_at' => $now,
  32. ]);
  33. $user = MiniUser::query()->where($identity)->lockForUpdate()->firstOrFail();
  34. if ((int) $user->status !== 1) {
  35. throw new ApiException(40302, '账号已停用', 403);
  36. }
  37. $token = bin2hex(random_bytes(32));
  38. $expires = date('Y-m-d H:i:s', time() + (int) config('mini_api.session_ttl', 604800));
  39. MiniSession::query()->insert([
  40. 'user_id' => $user->id,
  41. 'token_hash' => hash('sha256', $token),
  42. 'expires_at' => $expires,
  43. 'created_at' => $now,
  44. ]);
  45. return [
  46. 'access_token' => $token,
  47. 'token_type' => 'Bearer',
  48. 'expires_at' => $expires,
  49. 'user_id' => (string) $user->id,
  50. 'identities' => (new Access(new Principal((string) $user->id)))->identities(),
  51. ];
  52. });
  53. }
  54. public function logout(string $token): array
  55. {
  56. MiniSession::query()->where('token_hash', hash('sha256', $token))->whereNull('revoked_at')->update(['revoked_at' => date('Y-m-d H:i:s')]);
  57. return ['logged_out' => true];
  58. }
  59. }