- 新增 users.force_password_change 字段与迁移 - 用户新增/编辑/批量导入支持要求更改密码 - 登录后未改密用户仅允许访问改密相关接口
147 lines
4.9 KiB
PHP
147 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\User;
|
|
use hg\apidoc\annotation as Apidoc;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Validation\Rules\Password;
|
|
|
|
#[Apidoc\Title('认证模块')]
|
|
class AuthController extends Controller
|
|
{
|
|
public function __construct()
|
|
{
|
|
$this->middleware('auth:api')->except('login');
|
|
$this->middleware(function (Request $request, \Closure $next) {
|
|
/** @var User|null $user */
|
|
$user = Auth::guard('api')->user();
|
|
if (! $user || ! $user->force_password_change) {
|
|
return $next($request);
|
|
}
|
|
|
|
$allowed = [
|
|
'api/auth/me',
|
|
'api/auth/password',
|
|
'api/auth/logout',
|
|
];
|
|
|
|
if (in_array($request->path(), $allowed, true)) {
|
|
return $next($request);
|
|
}
|
|
|
|
return response()->json([
|
|
'code' => 423,
|
|
'message' => '请先修改密码后再继续操作',
|
|
'data' => ['force_password_change' => true],
|
|
], 423);
|
|
})->except('login');
|
|
}
|
|
|
|
#[Apidoc\Title('登录'), Apidoc\Method('POST'), Apidoc\Url('/auth/login')]
|
|
public function login(Request $request): JsonResponse
|
|
{
|
|
$validated = $request->validate([
|
|
'email' => ['nullable', 'email', 'required_without:phone'],
|
|
'phone' => ['nullable', 'string', 'max:32', 'required_without:email'],
|
|
'password' => ['required', 'string'],
|
|
]);
|
|
$credentials = ['password' => (string) $validated['password']];
|
|
$accountType = '';
|
|
|
|
if (! empty($validated['email'])) {
|
|
$credentials['email'] = (string) $validated['email'];
|
|
$accountType = 'email';
|
|
}
|
|
|
|
if (! empty($validated['phone'])) {
|
|
$credentials['phone'] = (string) $validated['phone'];
|
|
$accountType = 'phone';
|
|
}
|
|
|
|
$token = Auth::guard('api')->attempt($credentials);
|
|
|
|
if (! $token) {
|
|
return response()->json(['code' => 401, 'message' => '账号或密码错误', 'data' => null], 401);
|
|
}
|
|
|
|
$this->auditLog($request, 'login', ['metadata' => ['account_type' => $accountType]]);
|
|
|
|
return response()->json([
|
|
'code' => 0,
|
|
'message' => 'ok',
|
|
'data' => [
|
|
'token' => $token,
|
|
'type' => 'bearer',
|
|
'expires_in' => Auth::guard('api')->factory()->getTTL() * 60,
|
|
],
|
|
]);
|
|
}
|
|
|
|
#[Apidoc\Title('当前用户信息'), Apidoc\Method('GET'), Apidoc\Url('/auth/me')]
|
|
public function me(): JsonResponse
|
|
{
|
|
/** @var User $user */
|
|
$user = Auth::guard('api')->user();
|
|
|
|
return response()->json([
|
|
'code' => 0,
|
|
'message' => 'ok',
|
|
'data' => [
|
|
'user' => $user?->load('roles'),
|
|
'permissions' => $user?->getAllPermissions()->pluck('name')->values(),
|
|
'force_password_change' => (bool) ($user?->force_password_change ?? false),
|
|
],
|
|
]);
|
|
}
|
|
|
|
#[Apidoc\Title('更新个人信息'), Apidoc\Method('PUT'), Apidoc\Url('/auth/profile')]
|
|
public function updateProfile(Request $request): JsonResponse
|
|
{
|
|
/** @var User $user */
|
|
$user = Auth::guard('api')->user();
|
|
|
|
$validated = $request->validate([
|
|
'nickname' => ['sometimes', 'required', 'string', 'max:255'],
|
|
'email' => ['sometimes', 'required', 'email', 'max:255', 'unique:users,email,'.$user->id],
|
|
'phone' => ['nullable', 'string', 'max:32', 'unique:users,phone,'.$user->id],
|
|
]);
|
|
|
|
$user->update($validated);
|
|
$this->auditLog($request, 'profile_update');
|
|
|
|
return response()->json(['code' => 0, 'message' => 'ok', 'data' => $user->fresh(['roles'])]);
|
|
}
|
|
|
|
#[Apidoc\Title('修改密码'), Apidoc\Method('PUT'), Apidoc\Url('/auth/password')]
|
|
public function updatePassword(Request $request): JsonResponse
|
|
{
|
|
/** @var User $user */
|
|
$user = Auth::guard('api')->user();
|
|
|
|
$validated = $request->validate([
|
|
'current_password' => ['required', 'current_password:api'],
|
|
'password' => ['required', 'confirmed', Password::min(6)],
|
|
]);
|
|
|
|
$user->password = $validated['password'];
|
|
$user->force_password_change = false;
|
|
$user->save();
|
|
$this->auditLog($request, 'password_update');
|
|
|
|
return response()->json(['code' => 0, 'message' => 'ok', 'data' => null]);
|
|
}
|
|
|
|
#[Apidoc\Title('登出'), Apidoc\Method('POST'), Apidoc\Url('/auth/logout')]
|
|
public function logout(Request $request): JsonResponse
|
|
{
|
|
$this->auditLog($request, 'logout');
|
|
Auth::guard('api')->logout();
|
|
|
|
return response()->json(['code' => 0, 'message' => 'ok', 'data' => null]);
|
|
}
|
|
}
|