middleware('sanctum.jwt:admin', ['except' => ['login', 'sendSms', 'smsLogin']]); } /** * Create a new AuthController instance. * * @return void */ public function guard() { return auth()->guard($this->guard); } /** * @OA\Post( * path="/api/admin/auth/login", * tags={"后台管理"}, * summary="用户名密码登录", * description="", * @OA\Parameter(name="username", in="query", @OA\Schema(type="string"), required=true, description="用户名"), * @OA\Parameter(name="password", in="query", @OA\Schema(type="string"), required=true, description="密码"), * @OA\Response( * response="200", * description="用户名密码登录" * ) * ) */ public function login() { $credentials = request(['username', 'password']); if (!$token = $this->guard()->attempt($credentials)) { return $this->fail(StarterResponseCode::LOGIN_FAIL); } $user = $this->guard()->user(); $token = $user->createToken("token")->plainTextToken; // 加日志 OperateLog::addLogs($user, "用户[{$user->name}]登陆成功"); return $this->respondWithToken($token); } /** * @OA\Post( * path="/api/admin/auth/me", * tags={"后台管理"}, * summary="获取用户基本信息", * description="", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="获取用户基本信息" * ) * ) */ public function me() { $user = Admin::with(['department', 'roles'])->find($this->guard()->user()->id); return $this->success($user); } /** * @OA\Post( * path="/api/admin/auth/logout", * tags={"后台管理"}, * summary="退出登录", * description="", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="退出登录" * ) * ) */ public function logout() { $user = $this->guard()->user(); $user->tokens()->delete(); $this->guard()->logout(); // 加日志 OperateLog::addLogs($user, "用户[$user->name]退出登陆"); return $this->success(["msg" => "登出成功"]); } /** * @OA\Get( * path="/api/admin/auth/permissions", * tags={"后台管理"}, * summary="获取权限菜单", * description="", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="获取权限菜单" * ) * ) */ public function getPermissions() { $admin = $this->guard()->user(); $admin_permissions = $admin->getAllPermissions(); $all_permissions = (new Permission())->get()->toArray(); $permission_has_url_ids = $admin_permissions->filter(function ($item) { return $item->url && $item->visible ? true : false; })->pluck("id")->toArray(); foreach ($admin_permissions as $admin_permission) { $pids = get_pid($all_permissions, $admin_permission->id, "pid", $permission_has_url_ids); foreach ($pids as $pid) { if (in_array($pid, $permission_has_url_ids)) continue; $permission_has_url_ids[] = $pid; } } $admin_permissions = new Permission(); $admin_permissions = $admin_permissions->whereIn("id", $permission_has_url_ids); $admin_permissions = $admin_permissions->orderBy("sortnumber")->get(); $admin_permissions = $admin_permissions->toArray(); $roleIds = $this->guard()->user()->roles->pluck('id')->toArray(); foreach ($admin_permissions as &$item) { $item['has_auth_node_tags'] = []; $has_auth_node_tags = RoleHasPermission::whereIn('role_id', $roleIds) ->where('permission_id', $item['id']) ->get()->implode('auth_node_tags', ','); if ($has_auth_node_tags) { $item['has_auth_node_tags'] = array_filter(array_unique(explode(',', $has_auth_node_tags))); } } $admin_permissions = array2tree($admin_permissions); return response()->json($admin_permissions); } /** * @OA\Post( * path="/api/admin/auth/sms-login", * tags={"后台管理"}, * summary="验证码登陆", * description="", * @OA\RequestBody(required=true, @OA\JsonContent( * required={"mobile", "code", "challenge_id"}, * @OA\Property(property="mobile", type="string", example="13800138000"), * @OA\Property(property="code", type="string", example="123456"), * @OA\Property(property="challenge_id", type="string", format="uuid") * )), * @OA\Response( * response="200", * description="" * ) * ) */ public function smsLogin() { $all = request()->all(); $messages = [ 'mobile.required' => '手机号必填', 'mobile.digits' => '手机号格式错误', 'code.digits' => '验证码格式错误', ]; $validator = Validator::make($all, [ 'mobile' => 'required|digits:11', 'code' => 'required|digits:6', 'challenge_id' => 'required|uuid', ], $messages); if ($validator->fails()) { return $this->fail([StarterResponseCode::START_ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } $admin = Admin::where('mobile', $all['mobile'])->first(); $result = app(AdminSmsChallengeService::class)->verify( $all['challenge_id'], $all['mobile'], $all['code'], request()->ip(), $admin, (string) request()->userAgent() ); if (!$result['ok']) { return $this->fail([ResponseCode::ERROR_BUSINESS, $result['message']]); } $token = $admin->createToken("token")->plainTextToken; // 加日志 OperateLog::addLogs($admin, "用户[{$admin->name}]短信登陆成功"); return $this->respondWithToken($token); } /** * @OA\Post( * path="/api/admin/auth/send-sms", * tags={"后台管理"}, * summary="短信发送", * description="", * @OA\RequestBody(required=true, @OA\JsonContent( * required={"mobile"}, * @OA\Property(property="mobile", type="string", example="13800138000") * )), * @OA\Response( * response="200", * description="" * ) * ) */ public function sendSms() { $all = request()->all(); $messages = [ 'mobile.required' => '手机号必填', 'mobile.digits' => '手机号格式错误', ]; $validator = Validator::make($all, [ 'mobile' => 'required|digits:11', ], $messages); if ($validator->fails()) { return $this->fail([StarterResponseCode::START_ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } $service = app(AdminSmsChallengeService::class); $canSend = $service->canSend($all['mobile'], request()->ip()); $admin = Admin::where('mobile', $all['mobile'])->first(); $challengeId = null; if ($canSend && $admin) { $smsSign = Config::getValueByKey('sms_sign'); $challengeId = $service->issueChallenge($all['mobile'], request()->ip(), function ($code) use ($all, $smsSign) { $content = "{$smsSign}验证码{$code},您正在登陆苏州科技商学院信息化系统,请在5分钟内完成验证。"; try { return (bool) ymSms($all['mobile'], $content); } catch (\Throwable $e) { // Do not expose provider/network errors or the mobile number to the client. Log::error('admin_sms_provider_error', [ 'mobile_hash' => hash('sha256', (string) $all['mobile']), 'exception' => get_class($e), ]); return false; } }, (string) request()->userAgent()); } // Always return the same shape, including for unknown or throttled numbers. return $this->success([ 'message' => '如果手机号已登记,验证码将发送', 'challenge_id' => $challengeId ?: $service->issueDecoyChallenge($all['mobile'], request()->ip(), (string) request()->userAgent()), ]); } /** * Get the token array structure. * * @param string $token * * @return \Illuminate\Http\JsonResponse */ protected function respondWithToken($token) { $ttl = config("sanctum.expiration"); if ($ttl) { $expires_in = $ttl * 60; } else { $expires_in = null; } return $this->success([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => $expires_in ]); } }