Накатал базовую авторизацию
This commit is contained in:
parent
4eb5d8d5b8
commit
a31c8aed39
|
@ -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']);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
});
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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');
|
||||
|
|
Loading…
Reference in New Issue