| @@ -28,6 +28,7 @@ class LogoutController extends WebController | |||
| protected function run(Request $request): JsonResponse | |||
| { | |||
| Auth::logout(); | |||
| $this->sessionUser->switchEnd(); | |||
| return $this->successResponse(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,39 @@ | |||
| <?php | |||
| namespace App\Http\Controllers\Web\Auth; | |||
| use App\Http\Controllers\Web\WebController; | |||
| use App\Models\User; | |||
| use Illuminate\Http\JsonResponse; | |||
| use Illuminate\Http\Request; | |||
| class SwitchController extends WebController | |||
| { | |||
| public function name(): string | |||
| { | |||
| return "成り代わり"; | |||
| } | |||
| public function description(): string | |||
| { | |||
| return "成り代わりを行う"; | |||
| } | |||
| public function __construct(protected SwitchParam $param) | |||
| { | |||
| parent::__construct(); | |||
| } | |||
| protected function run(Request $request): JsonResponse | |||
| { | |||
| $param = $this->param; | |||
| $user = User::findOrFail($param->userId); | |||
| $this->sessionUser->switch($user); | |||
| return $this->successResponse(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| <?php | |||
| namespace App\Http\Controllers\Web\Auth; | |||
| use App\Http\Controllers\Web\WebController; | |||
| use Illuminate\Http\JsonResponse; | |||
| use Illuminate\Http\Request; | |||
| class SwitchEndController extends WebController | |||
| { | |||
| public function name(): string | |||
| { | |||
| return "成り代わりを終了する"; | |||
| } | |||
| public function description(): string | |||
| { | |||
| return "成り代わりを終了する"; | |||
| } | |||
| public function __construct(protected SwitchParam $param) | |||
| { | |||
| parent::__construct(); | |||
| } | |||
| protected function run(Request $request): JsonResponse | |||
| { | |||
| $this->sessionUser->switchEnd(); | |||
| return $this->successResponse(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| <?php | |||
| namespace App\Http\Controllers\Web\Auth; | |||
| use App\Http\Controllers\Web\NoneParams; | |||
| class SwitchParam extends NoneParams | |||
| { | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| <?php | |||
| namespace App\Http\Controllers\Web\Auth; | |||
| use App\Http\Controllers\Web\BaseParam; | |||
| /** | |||
| * @property string userId | |||
| */ | |||
| class SwitchParam extends BaseParam | |||
| { | |||
| public function rules(): array | |||
| { | |||
| return [ | |||
| 'user_id' => $this->str(), | |||
| ]; | |||
| } | |||
| } | |||
| @@ -8,6 +8,7 @@ use App\Codes\UserRole; | |||
| use App\Exceptions\AppCommonException; | |||
| use App\Exceptions\ExclusiveException; | |||
| use App\Exceptions\GeneralErrorMessageException; | |||
| use App\Sessions\SessionUser; | |||
| use App\Util\DBUtil; | |||
| use Exception; | |||
| use Illuminate\Foundation\Auth\Access\AuthorizesRequests; | |||
| @@ -79,6 +80,8 @@ abstract class WebController extends BaseController | |||
| protected DBUtil $transaction; | |||
| protected SessionUser $sessionUser; | |||
| /** | |||
| * 返却する結果コード | |||
| * | |||
| @@ -89,6 +92,7 @@ abstract class WebController extends BaseController | |||
| public function __construct() | |||
| { | |||
| $this->transaction = DBUtil::instance(); | |||
| $this->sessionUser = SessionUser::instance(); | |||
| } | |||
| @@ -168,8 +172,6 @@ abstract class WebController extends BaseController | |||
| $this->validated = $validator->validated(); | |||
| $this->getParam()->setData($this->validated); | |||
| $this->authorize(); | |||
| $this->transaction->beginTransaction(); | |||
| $ret = $this->run($request); | |||
| @@ -326,28 +328,6 @@ abstract class WebController extends BaseController | |||
| return $header; | |||
| } | |||
| // 以下 認可関係 | |||
| protected array|null $roleAllow = null; | |||
| protected array|null $roleDisallow = null; | |||
| protected array|null $customAllow = null; | |||
| protected function roleAllow(UserRole $role) | |||
| { | |||
| $this->roleAllow = []; | |||
| foreach (UserRole::cases() as $ele) { | |||
| if ($role->value <= $ele->value) { | |||
| $this->roleAllow[] = $ele; | |||
| } | |||
| } | |||
| } | |||
| private function authorize() | |||
| { | |||
| if (!Auth::check()) { | |||
| return; | |||
| } | |||
| } | |||
| // 返却用データの登録 | |||
| protected function setEmailId(int $emailId) | |||
| { | |||
| @@ -40,7 +40,7 @@ class Kernel extends HttpKernel | |||
| 'api' => [ | |||
| // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, | |||
| \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', | |||
| \Illuminate\Routing\Middleware\ThrottleRequests::class . ':api', | |||
| \Illuminate\Routing\Middleware\SubstituteBindings::class, | |||
| ], | |||
| ]; | |||
| @@ -64,5 +64,6 @@ class Kernel extends HttpKernel | |||
| 'signed' => \App\Http\Middleware\ValidateSignature::class, | |||
| 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, | |||
| 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, | |||
| 'role' => \App\Http\Middleware\RoleMiddleware::class, | |||
| ]; | |||
| } | |||
| @@ -0,0 +1,38 @@ | |||
| <?php | |||
| namespace App\Http\Middleware; | |||
| use App\Codes\UserRole; | |||
| use App\Sessions\SessionUser; | |||
| use Closure; | |||
| use Illuminate\Http\Request; | |||
| use Symfony\Component\HttpFoundation\Response; | |||
| class RoleMiddleware | |||
| { | |||
| public function __construct(private SessionUser $sessionUser) | |||
| { | |||
| } | |||
| /** | |||
| * Handle an incoming request. | |||
| * | |||
| * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next | |||
| */ | |||
| public function handle(Request $request, Closure $next, string $rolesStr): Response | |||
| { | |||
| $allowRoles = []; | |||
| foreach (explode(",", $rolesStr) as $roleSrt) { | |||
| $role = UserRole::from($roleSrt); | |||
| $allowRoles[] = $role; | |||
| } | |||
| if (in_array($this->sessionUser->user()->role, $allowRoles, true) === false) { | |||
| abort(403); | |||
| } | |||
| return $next($request); | |||
| } | |||
| } | |||
| @@ -2,20 +2,100 @@ | |||
| namespace App\Sessions; | |||
| use App\Codes\UserRole; | |||
| use App\Exceptions\AppCommonException; | |||
| use App\Features\InstanceAble; | |||
| use App\Models\HtpmsCustomer\HtpmsCustomerConnectionSwitch; | |||
| use App\Models\User; | |||
| use Illuminate\Auth\AuthenticationException; | |||
| use Illuminate\Support\Facades\Auth; | |||
| use Illuminate\Validation\UnauthorizedException; | |||
| use Illuminate\Support\Facades\Session; | |||
| use LogicException; | |||
| class SessionUser | |||
| { | |||
| use InstanceAble; | |||
| public function user() | |||
| private const KEY_成り代わりログインユーザーID = "KEY_成り代わりログインユーザーID"; | |||
| private User|null $user; | |||
| private bool $isSwtiched = false; | |||
| public function __construct() | |||
| { | |||
| // 認証していない場合はスキップ | |||
| $this->user = Auth::user(); | |||
| if ($this->user === null) { | |||
| return; | |||
| } | |||
| $userId = Session::get($this->getStoreKey(self::KEY_成り代わりログインユーザーID)); | |||
| if ($userId === null) { | |||
| return; | |||
| } | |||
| $user = User::find($userId); | |||
| if ($user) { | |||
| $this->user = $user; | |||
| if ($user->customer_id) { | |||
| HtpmsCustomerConnectionSwitch::switch($user->customer_id); | |||
| $this->isSwtiched = true; | |||
| } | |||
| } else { | |||
| logger("無効な成り代わり 破棄"); | |||
| $this->switchEnd(); | |||
| } | |||
| } | |||
| public function switch(User $targetUser): void | |||
| { | |||
| $user = Auth::user(); | |||
| if ($user === null) { | |||
| throw new UnauthorizedException(); | |||
| if ($user === null) throw new AuthenticationException(); | |||
| // 成り代わりできるかパターンチェック | |||
| if ($user->role === UserRole::ADMIN) { | |||
| if (in_array($targetUser->role, [UserRole::CUSTOMER, UserRole::SHOP], true) === false) { | |||
| throw new LogicException("不適切な成り代わり"); | |||
| } | |||
| } else if ($user->role === UserRole::CUSTOMER) { | |||
| if (in_array($targetUser->role, [UserRole::SHOP], true) === false) { | |||
| throw new LogicException("不適切な成り代わり"); | |||
| } | |||
| } else { | |||
| throw new LogicException("不適切な成り代わり"); | |||
| } | |||
| // 顧客IDチェック | |||
| if ($targetUser->customer_id === null) { | |||
| throw new AppCommonException("顧客IDがnullのため成り代わり不可"); | |||
| } | |||
| return $user; | |||
| Session::put($this->getStoreKey(self::KEY_成り代わりログインユーザーID), $targetUser->id); | |||
| HtpmsCustomerConnectionSwitch::switch($targetUser->customer_id); | |||
| $this->isSwtiched = true; | |||
| } | |||
| public function switchEnd() | |||
| { | |||
| $this->isSwtiched = false; | |||
| Session::remove($this->getStoreKey(self::KEY_成り代わりログインユーザーID)); | |||
| } | |||
| public function user(): ?User | |||
| { | |||
| return $this->user ?? Auth::user(); | |||
| } | |||
| public function isSwtiched(): bool | |||
| { | |||
| return $this->isSwtiched; | |||
| } | |||
| private function getStoreKey(string $key): string | |||
| { | |||
| return sprintf("%s-%s", self::class, $key); | |||
| } | |||
| } | |||
| @@ -2,6 +2,7 @@ | |||
| namespace App\Util; | |||
| use App\Codes\UserRole; | |||
| use Illuminate\Support\Facades\Route; | |||
| use Illuminate\Support\Str; | |||
| @@ -43,4 +44,18 @@ class RouteHelper | |||
| { | |||
| return Str::replaceFirst('/api', '', $route); | |||
| } | |||
| /** | |||
| * @param UserRole[] $roles | |||
| */ | |||
| static public function role(array $roles): string | |||
| { | |||
| $rolesStrArr = []; | |||
| foreach ($roles as $role) { | |||
| $rolesStrArr[] = $role->value; | |||
| } | |||
| return "role:" . implode(",", $rolesStrArr); | |||
| } | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| <?php | |||
| use App\Codes\UserRole; | |||
| use App\Util\RouteHelper; | |||
| use Illuminate\Support\Facades\Route; | |||
| @@ -15,10 +16,18 @@ use Illuminate\Support\Facades\Route; | |||
| */ | |||
| RouteHelper::post('/login', App\Http\Controllers\Web\Auth\LoginController::class); | |||
| RouteHelper::get('/logout', App\Http\Controllers\Web\Auth\LogoutController::class); | |||
| RouteHelper::get('/me', App\Http\Controllers\Web\Auth\MeController::class); | |||
| RouteHelper::get('/logout', App\Http\Controllers\Web\Auth\LogoutController::class); | |||
| RouteHelper::get('/qr-service/get-ticket', App\Http\Controllers\Web\QRService\CreateTicketController::class); | |||
| Route::middleware('auth:sanctum')->group(function () { | |||
| Route::middleware(RouteHelper::role([UserRole::ADMIN]))->group(function () { | |||
| }); | |||
| Route::middleware(RouteHelper::role([UserRole::ADMIN, UserRole::CUSTOMER]))->group(function () { | |||
| RouteHelper::post('/role/switch', App\Http\Controllers\Web\Auth\SwitchController::class); | |||
| RouteHelper::get('/role/switch/end', App\Http\Controllers\Web\Auth\SwitchEndController::class); | |||
| }); | |||
| }); | |||