AiModelTokenController.php 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Models\AiModel;
  4. use App\Services\AuthService;
  5. use App\Tools\OpsLog;
  6. use Illuminate\Http\JsonResponse;
  7. use Illuminate\Http\Request;
  8. /**
  9. * 签发 AI 模型的身份 token。
  10. *
  11. * 外部客户端(如 wikipali-write Skill)拿到该 token 后,即可以「模型身份」
  12. * 调用写入类端点,使 editor_uid 记为模型 uid 而非操作者本人。
  13. *
  14. * @see docs/wikipali-write-skill-design.md §5.1
  15. */
  16. class AiModelTokenController extends Controller
  17. {
  18. /**
  19. * 取得指定 AI 模型的 user token。
  20. *
  21. * 仅模型 owner 本人可调用(设计决策:模型只挂个人 studio,不支持 group studio)。
  22. * 签出的 token 有效期 30 天,可用 destroy() 提前撤销;属高敏感凭据,故记入 ops 日志。
  23. */
  24. public function show(Request $request, AiModel $aiModel): JsonResponse
  25. {
  26. $user = AuthService::current($request);
  27. if (! $user) {
  28. return $this->error(__('auth.failed'), null, 401);
  29. }
  30. if (! AiModelController::canEdit($user['user_uid'], $aiModel->owner_id)) {
  31. return $this->error(__('auth.failed'), null, 403);
  32. }
  33. $token = AuthService::getUserToken($aiModel->uid);
  34. if (! $token) {
  35. return $this->error('ai model not found', null, 404);
  36. }
  37. OpsLog::debug($user['user_uid'], [
  38. 'action' => 'ai-model-token.issue',
  39. 'model_uid' => $aiModel->uid,
  40. 'model_name' => $aiModel->name,
  41. ]);
  42. return $this->ok([
  43. 'uid' => $aiModel->uid,
  44. 'name' => $aiModel->name,
  45. 'token' => $token,
  46. ]);
  47. }
  48. /**
  49. * 撤销该模型已签出的全部身份 token。
  50. *
  51. * 版本号自增后,旧 token 里的 ver 立即对不上(见 AuthService::current())。
  52. * 无法只撤销其中一张——凭据泄漏时本就该全部作废。
  53. */
  54. public function destroy(Request $request, AiModel $aiModel): JsonResponse
  55. {
  56. $user = AuthService::current($request);
  57. if (! $user) {
  58. return $this->error(__('auth.failed'), null, 401);
  59. }
  60. if (! AiModelController::canEdit($user['user_uid'], $aiModel->owner_id)) {
  61. return $this->error(__('auth.failed'), null, 403);
  62. }
  63. $aiModel->increment('token_version');
  64. OpsLog::debug($user['user_uid'], [
  65. 'action' => 'ai-model-token.revoke',
  66. 'model_uid' => $aiModel->uid,
  67. 'model_name' => $aiModel->name,
  68. 'token_version' => (int) $aiModel->token_version,
  69. ]);
  70. return $this->ok([
  71. 'uid' => $aiModel->uid,
  72. 'name' => $aiModel->name,
  73. 'token_version' => (int) $aiModel->token_version,
  74. ]);
  75. }
  76. }