Накатал базовую авторизацию
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'" |                 :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="/" 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 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 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="/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> | ||||||
|             <v-sheet class="rounded-lg main-bg h-100 mt-3 mr-10 ml-10 mb-10 pa-5"> |             <v-sheet class="rounded-lg main-bg h-100 mt-3 mr-10 ml-10 mb-10 pa-5"> | ||||||
|                 <RouterView v-slot="{ Component }"> |                 <RouterView v-slot="{ Component }"> | ||||||
|  | @ -48,6 +49,7 @@ | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
| import {th} from "vuetify/locale"; | import {th} from "vuetify/locale"; | ||||||
|  | import {useAuthStore} from "./store/auth.js"; | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|     name: "App", |     name: "App", | ||||||
|  | @ -57,7 +59,19 @@ export default { | ||||||
|         isWide: window.innerWidth >= 460, |         isWide: window.innerWidth >= 460, | ||||||
|         menuOpen: false |         menuOpen: false | ||||||
|     }), |     }), | ||||||
|  |     computed: { | ||||||
|  |         user() { | ||||||
|  |             const authStore = useAuthStore(); | ||||||
|  |             return authStore.user; | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|     methods: { |     methods: { | ||||||
|  |         logout() { | ||||||
|  |             const authStore = useAuthStore(); | ||||||
|  |             authStore.logout(); | ||||||
|  |             this.username = 'guest'; | ||||||
|  |             this.$router.push('/login'); | ||||||
|  |         }, | ||||||
|         resizeEventHandler(e) { |         resizeEventHandler(e) { | ||||||
|             this.windowHeight = document.documentElement.clientHeight; |             this.windowHeight = document.documentElement.clientHeight; | ||||||
|             this.windowWidth = document.documentElement.clientWidth; |             this.windowWidth = document.documentElement.clientWidth; | ||||||
|  |  | ||||||
|  | @ -10,6 +10,9 @@ import Login from "./views/Login.vue"; | ||||||
| import About from "./views/About.vue"; | import About from "./views/About.vue"; | ||||||
| import Register from "./views/Register.vue"; | import Register from "./views/Register.vue"; | ||||||
| import {createMemoryHistory, createRouter} from "vue-router"; | import {createMemoryHistory, createRouter} from "vue-router"; | ||||||
|  | import { createPinia } from 'pinia'; | ||||||
|  | 
 | ||||||
|  | const pinia = createPinia(); | ||||||
| 
 | 
 | ||||||
| const routes = [ | const routes = [ | ||||||
|     {path: '/', component: About, props: true}, |     {path: '/', component: About, props: true}, | ||||||
|  | @ -27,4 +30,4 @@ const vuetify = createVuetify({ | ||||||
|     directives |     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> | <script> | ||||||
|  | import { useAuthStore } from '../store/auth.js'; | ||||||
| export default { | 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> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <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> | </template> | ||||||
| 
 | 
 | ||||||
| <style scoped> | <style scoped> | ||||||
|  |  | ||||||
|  | @ -1,6 +1,19 @@ | ||||||
| <template> | <template> | ||||||
|     <div class="w-100 h-100 d-flex justify-center"> |     <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'"> |         <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-label>Логин:</v-label> | ||||||
|             <v-text-field label="Логин" class="flex-grow-0"></v-text-field> |             <v-text-field label="Логин" class="flex-grow-0"></v-text-field> | ||||||
|             <v-label>Пароль:</v-label> |             <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'"> |                 <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> |                     <v-btn color="#F0A068FF" :class="isWide ? 'w-100' : 'w-100 text-body-1'">Регистрация</v-btn> | ||||||
|                 </router-link> |                 </router-link> | ||||||
|             </div> |             </div>--> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|  | import { useAuthStore } from '../store/auth.js'; | ||||||
| export default { | export default { | ||||||
|     name: "Login", |     name: "Login", | ||||||
|     props: { |     props: { | ||||||
|         isWide: Boolean |         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> | </script> | ||||||
|  |  | ||||||
|  | @ -1,8 +1,27 @@ | ||||||
| <script> | <script> | ||||||
|  | import { useAuthStore } from '../store/auth.js'; | ||||||
| export default { | export default { | ||||||
|     name: "Register", |     name: "Register", | ||||||
|     props: { |     props: { | ||||||
|         isWide: Boolean |         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> | </script> | ||||||
|  | @ -10,18 +29,20 @@ export default { | ||||||
| <template> | <template> | ||||||
|     <div class="w-100 h-100 d-flex justify-center"> |     <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'"> |         <div class="d-flex flex-column justify-center h-100" :class="isWide ? 'w-50' : 'w-75'"> | ||||||
|             <v-label>Логин:</v-label> |             <v-form @submit.prevent="register"> | ||||||
|             <v-text-field label="Логин" class="flex-grow-0"></v-text-field> |                 <v-label>Имя:</v-label> | ||||||
|             <v-label>E-mail:</v-label> |                 <v-text-field type="text" v-model="name" label="Имя" class="flex-grow-0" required></v-text-field> | ||||||
|             <v-text-field label="E-mail" class="flex-grow-0"></v-text-field> |                 <v-label>E-mail:</v-label> | ||||||
|             <v-label>Пароль:</v-label> |                 <v-text-field type="email" v-model="email" label="E-mail" class="flex-grow-0" required></v-text-field> | ||||||
|             <v-text-field label="Пароль" class="flex-grow-0"></v-text-field> |                 <v-label>Пароль:</v-label> | ||||||
|             <div class="d-flex justify-center" :class="isWide ? '' : 'flex-column align-center'"> |                 <v-text-field type="password" v-model="password" label="Пароль" class="flex-grow-0" required></v-text-field> | ||||||
|                 <v-btn color="#F0A068FF" class="ma-5" :class="isWide ? 'w-25' : 'w-100 text-body-1'">Зарегистрироваться</v-btn> |                 <div class="d-flex justify-center" :class="isWide ? '' : 'flex-column align-center'"> | ||||||
|                 <router-link to="/login" class="text-decoration-none link-no-color ma-5" :class="isWide ? 'w-25' : 'w-100'"> |                     <v-btn type="submit" color="#F0A068FF" class="ma-5" :class="isWide ? 'w-25' : 'w-100 text-body-1'" block>Зарегистрироваться</v-btn> | ||||||
|                     <v-btn color="#F0A068FF" :class="isWide ? 'w-100' : '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'"> | ||||||
|                 </router-link> |                         <v-btn color="#F0A068FF" :class="isWide ? 'w-100' : 'w-100 text-body-1'">Вход</v-btn> | ||||||
|             </div> |                     </router-link> | ||||||
|  |                 </div> | ||||||
|  |             </v-form> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| <?php | <?php | ||||||
| 
 | 
 | ||||||
|  | use App\Http\Controllers\API\AuthController; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Illuminate\Support\Facades\Route; | use Illuminate\Support\Facades\Route; | ||||||
| 
 | 
 | ||||||
|  | @ -17,3 +18,7 @@ | ||||||
| Route::middleware('auth:sanctum')->get('/user', function (Request $request) { | Route::middleware('auth:sanctum')->get('/user', function (Request $request) { | ||||||
|     return $request->user(); |     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