Require auth for the web UI, keep the JSON API open
Sites/Social Accounts/Posts pages now require login; add a Login Livewire component, guest layout, and logout action. routes/api.php is untouched, per AI_API.md's documented no-auth-by-design contract. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Auth;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Component;
|
||||
|
||||
#[Layout('components.layouts.guest')]
|
||||
class Login extends Component
|
||||
{
|
||||
public string $email = '';
|
||||
|
||||
public string $password = '';
|
||||
|
||||
public bool $remember = false;
|
||||
|
||||
public function login(): void
|
||||
{
|
||||
$credentials = $this->validate([
|
||||
'email' => ['required', 'email'],
|
||||
'password' => ['required'],
|
||||
]);
|
||||
|
||||
if (! Auth::attempt($credentials, $this->remember)) {
|
||||
$this->addError('email', 'These credentials do not match our records.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
request()->session()->regenerate();
|
||||
|
||||
$this->redirect(route('sites.index'), navigate: true);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.auth.login');
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,17 @@
|
||||
@livewireStyles
|
||||
</head>
|
||||
<body class="bg-gray-50 text-gray-900">
|
||||
<nav class="bg-white border-b border-gray-200 px-6 py-4 flex gap-6">
|
||||
<nav class="bg-white border-b border-gray-200 px-6 py-4 flex gap-6 items-center">
|
||||
<a href="{{ route('sites.index') }}" class="font-medium hover:text-blue-600">Sites</a>
|
||||
<a href="{{ route('social-accounts.index') }}" class="font-medium hover:text-blue-600">Social Accounts</a>
|
||||
<a href="{{ route('posts.index') }}" class="font-medium hover:text-blue-600">Posts</a>
|
||||
|
||||
@auth
|
||||
<form method="POST" action="{{ route('logout') }}" class="ml-auto">
|
||||
@csrf
|
||||
<button type="submit" class="text-sm text-gray-500 hover:text-gray-900">Log out</button>
|
||||
</form>
|
||||
@endauth
|
||||
</nav>
|
||||
|
||||
<main class="p-6">
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ $title ?? 'Muninn' }}</title>
|
||||
@vite('resources/css/app.css')
|
||||
@livewireStyles
|
||||
</head>
|
||||
<body class="bg-gray-50 text-gray-900 flex items-center justify-center min-h-screen">
|
||||
<main class="w-full max-w-sm px-4">
|
||||
{{ $slot }}
|
||||
</main>
|
||||
|
||||
@livewireScripts
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<div class="bg-white p-8 rounded-lg shadow border border-gray-200">
|
||||
<h1 class="text-xl font-semibold mb-6">Muninn</h1>
|
||||
|
||||
<form wire:submit="login" class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1" for="email">Email</label>
|
||||
<input type="email" id="email" wire:model="email" class="w-full rounded border-gray-300" autofocus>
|
||||
@error('email') <p class="text-sm text-red-600 mt-1">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1" for="password">Password</label>
|
||||
<input type="password" id="password" wire:model="password" class="w-full rounded border-gray-300">
|
||||
@error('password') <p class="text-sm text-red-600 mt-1">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
<label class="flex items-center gap-2 text-sm">
|
||||
<input type="checkbox" wire:model="remember">
|
||||
Remember me
|
||||
</label>
|
||||
|
||||
<button type="submit" class="w-full bg-blue-600 text-white rounded py-2 font-medium hover:bg-blue-700">
|
||||
Log in
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
+17
-3
@@ -1,14 +1,28 @@
|
||||
<?php
|
||||
|
||||
use App\Livewire\Auth\Login;
|
||||
use App\Livewire\Posts\Index as PostsIndex;
|
||||
use App\Livewire\Sites\Index as SitesIndex;
|
||||
use App\Livewire\SocialAccounts\Index as SocialAccountsIndex;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', function () {
|
||||
return view('welcome');
|
||||
});
|
||||
|
||||
Route::get('/sites', SitesIndex::class)->name('sites.index');
|
||||
Route::get('/social-accounts', SocialAccountsIndex::class)->name('social-accounts.index');
|
||||
Route::get('/posts', PostsIndex::class)->name('posts.index');
|
||||
Route::get('/login', Login::class)->middleware('guest')->name('login');
|
||||
|
||||
Route::post('/logout', function () {
|
||||
Auth::guard('web')->logout();
|
||||
request()->session()->invalidate();
|
||||
request()->session()->regenerateToken();
|
||||
|
||||
return redirect('/login');
|
||||
})->middleware('auth')->name('logout');
|
||||
|
||||
Route::middleware('auth')->group(function () {
|
||||
Route::get('/sites', SitesIndex::class)->name('sites.index');
|
||||
Route::get('/social-accounts', SocialAccountsIndex::class)->name('social-accounts.index');
|
||||
Route::get('/posts', PostsIndex::class)->name('posts.index');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user