wire auth api

This commit is contained in:
Yisroel Baum 2026-05-23 23:21:07 +03:00
parent 9e70fae38d
commit eff7c5c281
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
12 changed files with 137 additions and 19 deletions

View file

@ -2,23 +2,29 @@
namespace App\Providers; namespace App\Providers;
use App\Auth\BcryptPasswordHasher;
use App\Auth\Clock;
use App\Auth\PasswordHasher;
use App\Auth\RandomTokenGenerator;
use App\Auth\SystemClock;
use App\Auth\TokenGenerator;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {
/**
* Register any application services.
*/
public function register(): void public function register(): void
{ {
// $this->app->bind(
} PasswordHasher::class,
BcryptPasswordHasher::class,
/** );
* Bootstrap any application services. $this->app->bind(
*/ TokenGenerator::class,
public function boot(): void RandomTokenGenerator::class,
{ );
// $this->app->bind(
Clock::class,
SystemClock::class,
);
} }
} }

View file

@ -0,0 +1,24 @@
<?php
namespace App\Providers;
use App\Auth\EloquentSessionRepository;
use App\Auth\SessionRepository;
use App\User\EloquentUserRepository;
use App\User\UserRepository;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->bind(
UserRepository::class,
EloquentUserRepository::class
);
$this->app->bind(
SessionRepository::class,
EloquentSessionRepository::class
);
}
}

View file

@ -6,7 +6,8 @@ use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__)) return Application::configure(basePath: dirname(__DIR__))
->withRouting( ->withRouting(
commands: __DIR__.'/../routes/console.php', api: __DIR__ . '/../routes/api.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up', health: '/up',
) )
->withMiddleware(function (Middleware $middleware): void { ->withMiddleware(function (Middleware $middleware): void {

View file

@ -1,7 +1,9 @@
<?php <?php
use App\Providers\AppServiceProvider; use App\Providers\AppServiceProvider;
use App\Providers\RepositoryServiceProvider;
return [ return [
AppServiceProvider::class, AppServiceProvider::class,
RepositoryServiceProvider::class,
]; ];

View file

@ -12,11 +12,16 @@ $allowedOrigins = array_values(array_filter(array_map(
))); )));
return [ return [
'paths' => ['login', 'logout', 'me'], 'paths' => ['api/*'],
'allowed_methods' => ['GET', 'POST', 'OPTIONS'], 'allowed_methods' => ['GET', 'POST', 'OPTIONS'],
'allowed_origins' => $allowedOrigins, 'allowed_origins' => $allowedOrigins,
'allowed_origins_patterns' => [], 'allowed_origins_patterns' => [],
'allowed_headers' => ['Content-Type', 'X-Requested-With', 'Accept', 'Origin'], 'allowed_headers' => [
'Content-Type',
'X-Requested-With',
'Accept',
'Origin',
],
'exposed_headers' => [], 'exposed_headers' => [],
'max_age' => 0, 'max_age' => 0,
'supports_credentials' => true, 'supports_credentials' => true,

View file

@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('email')->unique();
$table->string('password_hash');
});
}
public function down(): void
{
Schema::dropIfExists('users');
}
};

View file

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('sessions', function (Blueprint $table) {
$table->string('token')->primary();
$table->foreignId('user_id')->constrained('users');
$table->dateTime('created_at');
$table->dateTime('expires_at');
});
}
public function down(): void
{
Schema::dropIfExists('sessions');
}
};

View file

@ -8,5 +8,8 @@ class DatabaseSeeder extends Seeder
{ {
public function run(): void public function run(): void
{ {
$this->call([
UserSeeder::class,
]);
} }
} }

View file

@ -0,0 +1,22 @@
<?php
namespace Database\Seeders;
use App\Auth\PasswordHasher;
use App\Shared\ValueObject\EmailAddress;
use App\User\CreateUserDto;
use App\User\UserRepository;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
public function run(): void
{
$userRepository = app(UserRepository::class);
$passwordHasher = app(PasswordHasher::class);
$userRepository->create(new CreateUserDto(
email: new EmailAddress('test@example.com'),
passwordHash: $passwordHasher->hash('password123!@#'),
));
}
}

10
backend/routes/api.php Normal file
View file

@ -0,0 +1,10 @@
<?php
use App\Controllers\AuthController;
use App\Http\Middleware\AuthMiddleware;
use Illuminate\Support\Facades\Route;
Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout', [AuthController::class, 'logout']);
Route::get('/me', [AuthController::class, 'me'])
->middleware(AuthMiddleware::class);

View file

@ -12,7 +12,7 @@ class CorsTest extends TestCase
'Origin' => 'https://rabbigerzi.com', 'Origin' => 'https://rabbigerzi.com',
'Access-Control-Request-Method' => 'POST', 'Access-Control-Request-Method' => 'POST',
'Access-Control-Request-Headers' => 'content-type', 'Access-Control-Request-Headers' => 'content-type',
])->options('/login'); ])->options('/api/login');
$response->assertNoContent(); $response->assertNoContent();
$response->assertHeader( $response->assertHeader(

View file

@ -20,7 +20,7 @@ export const useAuthStore = defineStore('auth', () => {
isSubmitting.value = true isSubmitting.value = true
try { try {
const response = await fetch(`${API_BASE_URL}/login`, { const response = await fetch(`${API_BASE_URL}/api/login`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
credentials: 'include', credentials: 'include',
@ -46,7 +46,7 @@ export const useAuthStore = defineStore('auth', () => {
async function fetchUser(): Promise<void> { async function fetchUser(): Promise<void> {
try { try {
const response = await fetch(`${API_BASE_URL}/me`, { const response = await fetch(`${API_BASE_URL}/api/me`, {
credentials: 'include', credentials: 'include',
}) })
@ -64,7 +64,7 @@ export const useAuthStore = defineStore('auth', () => {
async function logout(): Promise<void> { async function logout(): Promise<void> {
try { try {
await fetch(`${API_BASE_URL}/logout`, { await fetch(`${API_BASE_URL}/api/logout`, {
method: 'POST', method: 'POST',
credentials: 'include', credentials: 'include',
}) })