You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
5.6 KiB

1 month ago
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\AdminUser;
use App\Models\Competition;
use App\Models\CompetitionAdmin;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
class ManageAuthController extends Controller
{
public function login(Request $request): JsonResponse
{
$data = $request->validate([
'username' => ['required', 'string', 'max:64'],
'password' => ['required', 'string', 'max:255'],
'competition_slug' => ['required', 'string', 'max:64'],
]);
$competition = Competition::query()
->where('slug', $data['competition_slug'])
->first();
if ($competition === null) {
throw ValidationException::withMessages([
'competition_slug' => ['赛事不存在'],
]);
}
$platform = AdminUser::query()->where('username', $data['username'])->first();
if ($platform !== null) {
$this->assertActivePassword($platform, $data['password']);
$platform->forceFill(['last_login_at' => now()])->save();
$token = $platform->createToken('admin')->plainTextToken;
return response()->json($this->payload(
$token,
'platform',
[
'id' => $platform->id,
'username' => $platform->username,
'name' => $platform->name,
],
$competition,
));
}
$admin = CompetitionAdmin::query()
->where('competition_id', $competition->id)
->where('username', $data['username'])
->first();
if ($admin === null || $admin->status !== 'active') {
throw ValidationException::withMessages([
'username' => ['账号不存在或不可用'],
]);
}
$this->assertActivePassword($admin, $data['password']);
$admin->forceFill(['last_login_at' => now()])->save();
$admin->tokens()->where('name', 'manage')->delete();
$token = $admin->createToken('manage')->plainTextToken;
return response()->json($this->payload(
$token,
'competition',
[
'id' => $admin->id,
'username' => $admin->username,
'name' => $admin->name,
],
$competition,
));
}
public function me(Request $request): JsonResponse
{
$user = $request->user();
if ($user instanceof AdminUser) {
return response()->json([
'kind' => 'platform',
'user' => [
'id' => $user->id,
'username' => $user->username,
'name' => $user->name,
],
]);
}
/** @var CompetitionAdmin $user */
$user->load('competition:id,slug,name');
return response()->json([
'kind' => 'competition',
'user' => [
'id' => $user->id,
'username' => $user->username,
'name' => $user->name,
],
'competition' => [
'id' => $user->competition?->id,
'slug' => $user->competition?->slug,
'name' => $user->competition?->name,
],
]);
}
public function changePassword(Request $request): JsonResponse
{
$data = $request->validate([
'current_password' => ['required', 'string', 'max:255'],
'password' => ['required', 'string', 'min:6', 'max:255', 'confirmed'],
]);
$user = $request->user();
if (! $user instanceof AdminUser && ! $user instanceof CompetitionAdmin) {
abort(403);
}
$hash = $user->getAuthPassword();
if ($hash === null || $hash === '' || ! Hash::check($data['current_password'], $hash)) {
throw ValidationException::withMessages([
'current_password' => ['当前密码不正确'],
]);
}
$user->forceFill(['password_hash' => $data['password']])->save();
return response()->json(['message' => '密码已更新']);
}
private function assertActivePassword(AdminUser|CompetitionAdmin $user, string $password): void
{
if ($user instanceof AdminUser && $user->status !== 'active') {
throw ValidationException::withMessages([
'username' => ['账号不存在或不可用'],
]);
}
$hash = $user->getAuthPassword();
if ($hash === null || $hash === '') {
throw ValidationException::withMessages([
'username' => ['该账号未配置密码'],
]);
}
if (! Hash::check($password, $hash)) {
throw ValidationException::withMessages([
'username' => ['账号或密码错误'],
]);
}
}
/**
* @param array{id: int, username: ?string, name: ?string} $user
* @return array<string, mixed>
*/
private function payload(string $token, string $kind, array $user, Competition $competition): array
{
return [
'token_type' => 'Bearer',
'access_token' => $token,
'token' => $token,
'kind' => $kind,
'user' => $user,
'admin' => $user,
'competition' => [
'id' => $competition->id,
'slug' => $competition->slug,
'name' => $competition->name,
],
];
}
}