Накатал базовую авторизацию

This commit is contained in:
p.belezov 2024-08-19 17:49:52 +08:00
parent 4eb5d8d5b8
commit a31c8aed39
8 changed files with 203 additions and 18 deletions

View File

@ -0,0 +1,61 @@
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
class AuthController extends Controller
{
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => bcrypt($request->password),
]);
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
]);
}
public function login(Request $request)
{
if (!Auth::attempt($request->only('email', 'password'))) {
return response()->json(['message' => 'Invalid login details'], 401);
}
$user = User::where('email', $request['email'])->firstOrFail();
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
]);
}
public function logout(Request $request)
{
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => 'Logged out']);
}
}

View File

@ -31,8 +31,9 @@
:class="menuOpen ? 'mt-2 mb-2 pa-2' : 'mt-10 mb-3 pa-5'"
>
<p class="ml-3 mr-3" :class="menuOpen ? 'text-body-1' : 'text-h6'"><RouterLink to="/" class="nav-link text-decoration-none">Главная</RouterLink></p>
<p class="ml-3 mr-3" :class="menuOpen ? 'text-body-1' : 'text-h6'"><RouterLink to="/login" class="nav-link text-decoration-none">Войти</RouterLink></p>
<p class="ml-3 mr-3" :class="menuOpen ? 'text-body-1' : 'text-h6'"><RouterLink to="/register" class="nav-link text-decoration-none">Регистрация</RouterLink></p>
<p v-if="user == null" class="ml-3 mr-3" :class="menuOpen ? 'text-body-1' : 'text-h6'"><RouterLink to="/login" class="nav-link text-decoration-none">Войти</RouterLink></p>
<p v-if="user == null" class="ml-3 mr-3" :class="menuOpen ? 'text-body-1' : 'text-h6'"><RouterLink to="/register" class="nav-link text-decoration-none">Регистрация</RouterLink></p>
<p v-else class="ml-3 mr-3" :class="menuOpen ? 'text-body-1' : 'text-h6'"><a href="#" class="nav-link text-decoration-none" @click="logout">Выйти</a></p>
</v-sheet>
<v-sheet class="rounded-lg main-bg h-100 mt-3 mr-10 ml-10 mb-10 pa-5">
<RouterView v-slot="{ Component }">
@ -48,6 +49,7 @@
<script>
import {th} from "vuetify/locale";
import {useAuthStore} from "./store/auth.js";
export default {
name: "App",
@ -57,7 +59,19 @@ export default {
isWide: window.innerWidth >= 460,
menuOpen: false
}),
computed: {
user() {
const authStore = useAuthStore();
return authStore.user;
},
},
methods: {
logout() {
const authStore = useAuthStore();
authStore.logout();
this.username = 'guest';
this.$router.push('/login');
},
resizeEventHandler(e) {
this.windowHeight = document.documentElement.clientHeight;
this.windowWidth = document.documentElement.clientWidth;

View File

@ -10,6 +10,9 @@ import Login from "./views/Login.vue";
import About from "./views/About.vue";
import Register from "./views/Register.vue";
import {createMemoryHistory, createRouter} from "vue-router";
import { createPinia } from 'pinia';
const pinia = createPinia();
const routes = [
{path: '/', component: About, props: true},
@ -27,4 +30,4 @@ const vuetify = createVuetify({
directives
})
createApp(App).use(vuetify).use(router).mount("#app")
createApp(App).use(vuetify).use(router).use(pinia).mount("#app")

31
resources/store/auth.js Normal file
View File

@ -0,0 +1,31 @@
import { defineStore } from 'pinia';
import axios from 'axios';
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null,
token: localStorage.getItem('token') || null,
}),
actions: {
async login(credentials) {
const response = await axios.post('/api/login', credentials);
this.user = response.data.user;
this.token = response.data.token;
localStorage.setItem('token', response.data.token);
},
async register(credentials) {
const response = await axios.post('/api/register', credentials);
this.user = response.data.user;
this.token = response.data.token;
localStorage.setItem('token', response.data.token);
},
logout() {
this.user = null;
this.token = null;
localStorage.removeItem('token');
},
},
getters: {
isAuthenticated: (state) => !!state.token,
},
});

View File

@ -1,11 +1,31 @@
<script>
import { useAuthStore } from '../store/auth.js';
export default {
name: "About"
name: "About",
data() {
return {
username: 'guest'
};
},
computed: {
user() {
const authStore = useAuthStore();
return authStore.user;
},
},
methods: {
logout() {
const authStore = useAuthStore();
authStore.logout();
this.username = 'guest';
this.$router.push('/login');
},
}
}
</script>
<template>
<v-label class="text-h3">Hello World!</v-label>
<v-label class="text-h3">Welcome {{ user != null ? user.name : 'guest' }}!</v-label><br>
</template>
<style scoped>

View File

@ -1,6 +1,19 @@
<template>
<div class="w-100 h-100 d-flex justify-center">
<div class="d-flex flex-column justify-center h-100" :class="isWide ? 'w-50' : 'w-75'">
<v-form @submit.prevent="login">
<v-label>Логин:</v-label>
<v-text-field type="email" v-model="email" label="E-mail" class="flex-grow-0" required></v-text-field>
<v-label>Пароль:</v-label>
<v-text-field type="password" v-model="password" label="Пароль" class="flex-grow-0" required></v-text-field>
<div class="d-flex justify-center" :class="isWide ? '' : 'flex-column align-center'">
<v-btn type="submit" color="#F0A068FF" class="ma-5 flex-grow-0" :class="isWide ? 'w-25' : 'w-100 text-body-1'" block>Войти</v-btn>
<router-link to="/register" class="text-decoration-none link-no-color ma-5" :class="isWide ? 'w-25' : 'w-100'">
<v-btn color="#F0A068FF" :class="isWide ? 'w-100' : 'w-100 text-body-1'">Регистрация</v-btn>
</router-link>
</div>
</v-form>
<!--
<v-label>Логин:</v-label>
<v-text-field label="Логин" class="flex-grow-0"></v-text-field>
<v-label>Пароль:</v-label>
@ -10,16 +23,33 @@
<router-link to="/register" class="text-decoration-none link-no-color ma-5" :class="isWide ? 'w-25' : 'w-100'">
<v-btn color="#F0A068FF" :class="isWide ? 'w-100' : 'w-100 text-body-1'">Регистрация</v-btn>
</router-link>
</div>
</div>-->
</div>
</div>
</template>
<script>
import { useAuthStore } from '../store/auth.js';
export default {
name: "Login",
props: {
isWide: Boolean
},
data() {
return {
email: '',
password: '',
};
},
methods: {
async login() {
const authStore = useAuthStore();
await authStore.login({
email: this.email,
password: this.password,
});
this.$router.push('/');
},
}
}
</script>

View File

@ -1,8 +1,27 @@
<script>
import { useAuthStore } from '../store/auth.js';
export default {
name: "Register",
props: {
isWide: Boolean
},
data() {
return {
name: '',
email: '',
password: '',
};
},
methods: {
async register() {
const authStore = useAuthStore();
await authStore.register({
name: this.name,
email: this.email,
password: this.password,
});
this.$router.push('/');
},
}
}
</script>
@ -10,18 +29,20 @@ export default {
<template>
<div class="w-100 h-100 d-flex justify-center">
<div class="d-flex flex-column justify-center h-100" :class="isWide ? 'w-50' : 'w-75'">
<v-label>Логин:</v-label>
<v-text-field label="Логин" class="flex-grow-0"></v-text-field>
<v-label>E-mail:</v-label>
<v-text-field label="E-mail" class="flex-grow-0"></v-text-field>
<v-label>Пароль:</v-label>
<v-text-field label="Пароль" class="flex-grow-0"></v-text-field>
<div class="d-flex justify-center" :class="isWide ? '' : 'flex-column align-center'">
<v-btn color="#F0A068FF" class="ma-5" :class="isWide ? 'w-25' : 'w-100 text-body-1'">Зарегистрироваться</v-btn>
<router-link to="/login" class="text-decoration-none link-no-color ma-5" :class="isWide ? 'w-25' : 'w-100'">
<v-btn color="#F0A068FF" :class="isWide ? 'w-100' : 'w-100 text-body-1'">Вход</v-btn>
</router-link>
</div>
<v-form @submit.prevent="register">
<v-label>Имя:</v-label>
<v-text-field type="text" v-model="name" label="Имя" class="flex-grow-0" required></v-text-field>
<v-label>E-mail:</v-label>
<v-text-field type="email" v-model="email" label="E-mail" class="flex-grow-0" required></v-text-field>
<v-label>Пароль:</v-label>
<v-text-field type="password" v-model="password" label="Пароль" class="flex-grow-0" required></v-text-field>
<div class="d-flex justify-center" :class="isWide ? '' : 'flex-column align-center'">
<v-btn type="submit" color="#F0A068FF" class="ma-5" :class="isWide ? 'w-25' : 'w-100 text-body-1'" block>Зарегистрироваться</v-btn>
<router-link to="/login" class="text-decoration-none link-no-color ma-5" :class="isWide ? 'w-25' : 'w-100'">
<v-btn color="#F0A068FF" :class="isWide ? 'w-100' : 'w-100 text-body-1'">Вход</v-btn>
</router-link>
</div>
</v-form>
</div>
</div>
</template>

View File

@ -1,5 +1,6 @@
<?php
use App\Http\Controllers\API\AuthController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
@ -17,3 +18,7 @@ use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum');