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
|
@livewireStyles
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-50 text-gray-900">
|
<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('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('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>
|
<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>
|
</nav>
|
||||||
|
|
||||||
<main class="p-6">
|
<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
|
<?php
|
||||||
|
|
||||||
|
use App\Livewire\Auth\Login;
|
||||||
use App\Livewire\Posts\Index as PostsIndex;
|
use App\Livewire\Posts\Index as PostsIndex;
|
||||||
use App\Livewire\Sites\Index as SitesIndex;
|
use App\Livewire\Sites\Index as SitesIndex;
|
||||||
use App\Livewire\SocialAccounts\Index as SocialAccountsIndex;
|
use App\Livewire\SocialAccounts\Index as SocialAccountsIndex;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return view('welcome');
|
return view('welcome');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/sites', SitesIndex::class)->name('sites.index');
|
Route::get('/login', Login::class)->middleware('guest')->name('login');
|
||||||
Route::get('/social-accounts', SocialAccountsIndex::class)->name('social-accounts.index');
|
|
||||||
Route::get('/posts', PostsIndex::class)->name('posts.index');
|
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