feat(认证与用户): 新增账号申请并支持批量分配角色权限
This commit is contained in:
parent
239e0edd05
commit
ce907ee7c4
@ -9,13 +9,14 @@ use Illuminate\Http\JsonResponse;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Validation\Rules\Password;
|
use Illuminate\Validation\Rules\Password;
|
||||||
|
use Spatie\Permission\Models\Role;
|
||||||
|
|
||||||
#[Apidoc\Title('认证模块')]
|
#[Apidoc\Title('认证模块')]
|
||||||
class AuthController extends Controller
|
class AuthController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware('auth:api')->except('login');
|
$this->middleware('auth:api')->except(['login', 'applyAccount']);
|
||||||
$this->middleware(function (Request $request, \Closure $next) {
|
$this->middleware(function (Request $request, \Closure $next) {
|
||||||
/** @var User|null $user */
|
/** @var User|null $user */
|
||||||
$user = Auth::guard('api')->user();
|
$user = Auth::guard('api')->user();
|
||||||
@ -41,7 +42,7 @@ class AuthController extends Controller
|
|||||||
'message' => '请先修改密码后再继续操作',
|
'message' => '请先修改密码后再继续操作',
|
||||||
'data' => ['force_password_change' => true],
|
'data' => ['force_password_change' => true],
|
||||||
], 423);
|
], 423);
|
||||||
})->except('login');
|
})->except(['login', 'applyAccount']);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('登录'), Apidoc\Method('POST'), Apidoc\Url('/auth/login')]
|
#[Apidoc\Title('登录'), Apidoc\Method('POST'), Apidoc\Url('/auth/login')]
|
||||||
@ -71,6 +72,19 @@ class AuthController extends Controller
|
|||||||
return response()->json(['code' => 401, 'message' => '账号或密码错误', 'data' => null], 401);
|
return response()->json(['code' => 401, 'message' => '账号或密码错误', 'data' => null], 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var User|null $user */
|
||||||
|
$user = Auth::guard('api')->user();
|
||||||
|
$permissionCount = (int) ($user?->getAllPermissions()->count() ?? 0);
|
||||||
|
if ($permissionCount <= 0) {
|
||||||
|
Auth::guard('api')->logout();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'code' => 403,
|
||||||
|
'message' => '账号申请已通过,但尚未开通任何权限,请联系管理员分配权限后再登录',
|
||||||
|
'data' => null,
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
$this->auditLog($request, 'login', ['metadata' => ['account_type' => $accountType]]);
|
$this->auditLog($request, 'login', ['metadata' => ['account_type' => $accountType]]);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -84,6 +98,39 @@ class AuthController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Apidoc\Title('账号申请'), Apidoc\Method('POST'), Apidoc\Url('/auth/apply-account')]
|
||||||
|
public function applyAccount(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$validated = $request->validate([
|
||||||
|
'nickname' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
|
||||||
|
'phone' => ['required', 'string', 'max:32', 'unique:users,phone'],
|
||||||
|
'password' => ['required', 'confirmed', Password::min(6)],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = User::query()->create([
|
||||||
|
'nickname' => $validated['nickname'],
|
||||||
|
'email' => $validated['email'],
|
||||||
|
'phone' => $validated['phone'],
|
||||||
|
'password' => $validated['password'],
|
||||||
|
'force_password_change' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$guestRole = Role::query()->firstOrCreate(
|
||||||
|
['name' => 'guest', 'guard_name' => 'api'],
|
||||||
|
['name' => 'guest', 'guard_name' => 'api']
|
||||||
|
);
|
||||||
|
$user->syncRoles([$guestRole->id]);
|
||||||
|
|
||||||
|
$this->auditLog($request, 'account_apply', ['metadata' => ['target_user_id' => $user->id]]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'code' => 0,
|
||||||
|
'message' => '申请提交成功,请联系或等待管理员开通权限后登录控制台',
|
||||||
|
'data' => null,
|
||||||
|
], 201);
|
||||||
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('当前用户信息'), Apidoc\Method('GET'), Apidoc\Url('/auth/me')]
|
#[Apidoc\Title('当前用户信息'), Apidoc\Method('GET'), Apidoc\Url('/auth/me')]
|
||||||
public function me(): JsonResponse
|
public function me(): JsonResponse
|
||||||
{
|
{
|
||||||
|
|||||||
@ -26,9 +26,14 @@ class BastionAccountController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('账号列表'), Apidoc\Method('GET'), Apidoc\Url('/accounts')]
|
#[Apidoc\Title('账号列表'), Apidoc\Method('GET'), Apidoc\Url('/accounts')]
|
||||||
public function index(): JsonResponse
|
public function index(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
return response()->json(['code' => 0, 'message' => 'ok', 'data' => BastionAccount::query()->latest()->paginate(20)]);
|
$validated = $request->validate([
|
||||||
|
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
||||||
|
]);
|
||||||
|
$perPage = (int) ($validated['per_page'] ?? 20);
|
||||||
|
|
||||||
|
return response()->json(['code' => 0, 'message' => 'ok', 'data' => BastionAccount::query()->latest()->paginate($perPage)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('创建账号'), Apidoc\Method('POST'), Apidoc\Url('/accounts')]
|
#[Apidoc\Title('创建账号'), Apidoc\Method('POST'), Apidoc\Url('/accounts')]
|
||||||
|
|||||||
@ -22,9 +22,13 @@ class PermissionController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('权限列表'), Apidoc\Method('GET'), Apidoc\Url('/permissions')]
|
#[Apidoc\Title('权限列表'), Apidoc\Method('GET'), Apidoc\Url('/permissions')]
|
||||||
public function index(): JsonResponse
|
public function index(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$permissions = Permission::query()->latest()->paginate(200);
|
$validated = $request->validate([
|
||||||
|
'per_page' => ['nullable', 'integer', 'min:1', 'max:200'],
|
||||||
|
]);
|
||||||
|
$perPage = (int) ($validated['per_page'] ?? 20);
|
||||||
|
$permissions = Permission::query()->latest()->paginate($perPage);
|
||||||
|
|
||||||
$permissions->getCollection()->transform(function (Permission $permission) {
|
$permissions->getCollection()->transform(function (Permission $permission) {
|
||||||
return $this->applyDefaultMeta($permission);
|
return $this->applyDefaultMeta($permission);
|
||||||
|
|||||||
@ -21,9 +21,13 @@ class RoleController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('角色列表'), Apidoc\Method('GET'), Apidoc\Url('/roles')]
|
#[Apidoc\Title('角色列表'), Apidoc\Method('GET'), Apidoc\Url('/roles')]
|
||||||
public function index(): JsonResponse
|
public function index(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$roles = Role::query()->with('permissions')->latest()->paginate(20);
|
$validated = $request->validate([
|
||||||
|
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
||||||
|
]);
|
||||||
|
$perPage = (int) ($validated['per_page'] ?? 20);
|
||||||
|
$roles = Role::query()->with('permissions')->latest()->paginate($perPage);
|
||||||
|
|
||||||
return response()->json(['code' => 0, 'message' => 'ok', 'data' => $roles]);
|
return response()->json(['code' => 0, 'message' => 'ok', 'data' => $roles]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class UserController extends Controller
|
|||||||
{
|
{
|
||||||
$this->middleware('auth:api');
|
$this->middleware('auth:api');
|
||||||
$this->middleware('permission:platform.users.view,api')->only(['index', 'show']);
|
$this->middleware('permission:platform.users.view,api')->only(['index', 'show']);
|
||||||
$this->middleware('permission:platform.users.manage,api')->only(['store', 'update', 'destroy', 'syncPermissions', 'import', 'importTemplate']);
|
$this->middleware('permission:platform.users.manage,api')->only(['store', 'update', 'destroy', 'syncPermissions', 'syncBatchAssignments', 'import', 'importTemplate']);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('用户列表'), Apidoc\Method('GET'), Apidoc\Url('/users')]
|
#[Apidoc\Title('用户列表'), Apidoc\Method('GET'), Apidoc\Url('/users')]
|
||||||
@ -71,8 +71,12 @@ class UserController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('更新用户'), Apidoc\Method('PUT'), Apidoc\Url('/users/{id}')]
|
#[Apidoc\Title('更新用户'), Apidoc\Method('PUT'), Apidoc\Url('/users/{id}')]
|
||||||
public function update(UpdateUserRequest $request, int $id): JsonResponse
|
public function update(UpdateUserRequest $request, string $id): JsonResponse
|
||||||
{
|
{
|
||||||
|
if ($id === 'batch-assignments') {
|
||||||
|
return $this->syncBatchAssignments($request);
|
||||||
|
}
|
||||||
|
|
||||||
$user = User::query()->findOrFail($id);
|
$user = User::query()->findOrFail($id);
|
||||||
$user->fill($request->safe()->except(['role_ids']));
|
$user->fill($request->safe()->except(['role_ids']));
|
||||||
|
|
||||||
@ -108,6 +112,46 @@ class UserController extends Controller
|
|||||||
return response()->json(['code' => 0, 'message' => 'ok', 'data' => $user->load(['roles', 'permissions'])]);
|
return response()->json(['code' => 0, 'message' => 'ok', 'data' => $user->load(['roles', 'permissions'])]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Apidoc\Title('批量设置用户组和用户权限'), Apidoc\Method('PUT'), Apidoc\Url('/users/batch-assignments')]
|
||||||
|
public function syncBatchAssignments(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$validated = $request->validate([
|
||||||
|
'user_ids' => ['required', 'array', 'min:1'],
|
||||||
|
'user_ids.*' => ['integer', 'exists:users,id'],
|
||||||
|
'role_ids' => ['present', 'array'],
|
||||||
|
'role_ids.*' => ['integer', 'exists:roles,id'],
|
||||||
|
'permission_ids' => ['present', 'array'],
|
||||||
|
'permission_ids.*' => ['integer', 'exists:permissions,id'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$userIds = collect($validated['user_ids'])->map(fn (int $id): int => (int) $id)->unique()->values()->all();
|
||||||
|
$roleIds = collect($validated['role_ids'])->map(fn (int $id): int => (int) $id)->unique()->values()->all();
|
||||||
|
$permissionIds = collect($validated['permission_ids'])->map(fn (int $id): int => (int) $id)->unique()->values()->all();
|
||||||
|
|
||||||
|
$users = User::query()->whereIn('id', $userIds)->get();
|
||||||
|
foreach ($users as $user) {
|
||||||
|
$user->syncRoles($roleIds);
|
||||||
|
$user->syncPermissions($permissionIds);
|
||||||
|
$this->syncServerResourcePermissionsByDirectPermissions($user, $permissionIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->auditLog($request, 'users_batch_assignments_update', [
|
||||||
|
'metadata' => [
|
||||||
|
'target_user_ids' => $userIds,
|
||||||
|
'role_ids' => $roleIds,
|
||||||
|
'permission_ids' => $permissionIds,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'code' => 0,
|
||||||
|
'message' => 'ok',
|
||||||
|
'data' => [
|
||||||
|
'updated_count' => $users->count(),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
#[Apidoc\Title('删除用户'), Apidoc\Method('DELETE'), Apidoc\Url('/users/{id}')]
|
#[Apidoc\Title('删除用户'), Apidoc\Method('DELETE'), Apidoc\Url('/users/{id}')]
|
||||||
public function destroy(Request $request, int $id): JsonResponse
|
public function destroy(Request $request, int $id): JsonResponse
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user