TokenController.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. <?php
  2. namespace App\Module\OAuth\Controllers;
  3. use App\Http\Controllers\Controller;
  4. use App\Module\OAuth\Services\OAuth;
  5. use App\Module\User\Models\User;
  6. use Illuminate\Http\Request;
  7. use Illuminate\Http\JsonResponse;
  8. use Illuminate\Support\Facades\Hash;
  9. class TokenController extends Controller
  10. {
  11. /**
  12. * 令牌端点
  13. */
  14. public function token(Request $request): JsonResponse
  15. {
  16. // 验证请求参数
  17. $request->validate([
  18. 'grant_type' => 'required|in:authorization_code,password,client_credentials,refresh_token',
  19. 'client_id' => 'required|string',
  20. 'client_secret' => 'required|string',
  21. ]);
  22. // 验证客户端
  23. if (!OAuth::validateClient($request->client_id, $request->client_secret, $request->grant_type)) {
  24. return response()->json([
  25. 'error' => 'invalid_client',
  26. 'error_description' => '无效的客户端凭证'
  27. ], 401);
  28. }
  29. // 根据授权类型处理
  30. switch ($request->grant_type) {
  31. case 'authorization_code':
  32. return $this->handleAuthorizationCode($request);
  33. case 'password':
  34. return $this->handlePassword($request);
  35. case 'client_credentials':
  36. return $this->handleClientCredentials($request);
  37. case 'refresh_token':
  38. return $this->handleRefreshToken($request);
  39. }
  40. }
  41. /**
  42. * 处理授权码模式
  43. */
  44. protected function handleAuthorizationCode(Request $request): JsonResponse
  45. {
  46. $request->validate([
  47. 'code' => 'required|string',
  48. 'redirect_uri' => 'required|url'
  49. ]);
  50. // 获取并验证授权码
  51. $codeKey = 'oauth_auth_code:' . $request->code;
  52. $codeData = cache()->get($codeKey);
  53. if (!$codeData) {
  54. return response()->json([
  55. 'error' => 'invalid_grant',
  56. 'error_description' => '无效的授权码'
  57. ], 400);
  58. }
  59. // 验证客户端ID和回调地址
  60. if ($codeData['client_id'] !== $request->client_id ||
  61. $codeData['redirect_uri'] !== $request->redirect_uri) {
  62. return response()->json([
  63. 'error' => 'invalid_grant',
  64. 'error_description' => '授权码验证失败'
  65. ], 400);
  66. }
  67. // 删除使用过的授权码
  68. cache()->delete($codeKey);
  69. // 创建访问令牌
  70. $token = OAuth::createAccessToken(
  71. $request->client_id,
  72. $codeData['user_id'],
  73. $codeData['scope'] ? explode(' ', $codeData['scope']) : []
  74. );
  75. return $this->tokenResponse($token);
  76. }
  77. /**
  78. * 处理密码模式
  79. */
  80. protected function handlePassword(Request $request): JsonResponse
  81. {
  82. $request->validate([
  83. 'username' => 'required|string',
  84. 'password' => 'required|string',
  85. 'scope' => 'nullable|string'
  86. ]);
  87. // 验证用户凭证
  88. $user = User::query()->where('email', $request->username)->first();
  89. if (!$user || !Hash::check($request->password, $user->password)) {
  90. return response()->json([
  91. 'error' => 'invalid_grant',
  92. 'error_description' => '无效的用户凭证'
  93. ], 400);
  94. }
  95. // 创建访问令牌
  96. $token = OAuth::createAccessToken(
  97. $request->client_id,
  98. $user->id,
  99. $request->scope ? explode(' ', $request->scope) : []
  100. );
  101. return $this->tokenResponse($token);
  102. }
  103. /**
  104. * 处理客户端模式
  105. */
  106. protected function handleClientCredentials(Request $request): JsonResponse
  107. {
  108. $request->validate([
  109. 'scope' => 'nullable|string'
  110. ]);
  111. // 创建访问令牌(不关联用户)
  112. $token = OAuth::createAccessToken(
  113. $request->client_id,
  114. null,
  115. $request->scope ? explode(' ', $request->scope) : []
  116. );
  117. return $this->tokenResponse($token);
  118. }
  119. /**
  120. * 处理刷新令牌
  121. */
  122. protected function handleRefreshToken(Request $request): JsonResponse
  123. {
  124. $request->validate([
  125. 'refresh_token' => 'required|string'
  126. ]);
  127. // TODO: 实现刷新令牌逻辑
  128. return response()->json([
  129. 'error' => 'unsupported_grant_type',
  130. 'error_description' => '暂不支持刷新令牌'
  131. ], 400);
  132. }
  133. /**
  134. * 格式化令牌响应
  135. */
  136. protected function tokenResponse($token): JsonResponse
  137. {
  138. return response()->json([
  139. 'access_token' => $token->access_token,
  140. 'token_type' => 'Bearer',
  141. 'expires_in' => $token->expires_at->diffInSeconds(now()),
  142. 'scope' => implode(' ', $token->scope ?? []),
  143. ]);
  144. }
  145. }