Feature/Auth: implement user authentication #3
49
client/src/api/AuthApi.ts
Normal file
49
client/src/api/AuthApi.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
// service to interact with the api/auth endpoints
|
||||||
|
// handles user registration, user logins, tokens, password reset, etc.
|
||||||
|
|
||||||
|
import api from "./axios.ts"
|
||||||
|
import type { User } from "../models/User.ts";
|
||||||
|
|
||||||
|
const API_URL: string = "/auth";
|
||||||
|
|
||||||
|
export const register = async (user: { username: string; email: string; password: string }) => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await api.post(`${API_URL}/register`, user);
|
||||||
|
|
||||||
|
// TODO: if valid
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// else return false
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const login = async (user: { username: string; password: string }) => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await api.post(`${API_URL}/login`, user);
|
||||||
|
const token = response.data.token;
|
||||||
|
|
||||||
|
localStorage.setItem("token", token);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logout = () => {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getToken = () => {
|
||||||
|
return localStorage.getItem("token");
|
||||||
|
}
|
||||||
24
client/src/api/axios.ts
Normal file
24
client/src/api/axios.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
// http service hub
|
||||||
|
// handles interceptors and such
|
||||||
|
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const baseUrl: string = import.meta.env.DEV ? import.meta.env.VITE_DEV_API_URL : "https://app.vxbard.net/api"
|
||||||
|
const api = axios.create({
|
||||||
|
baseURL: baseUrl
|
||||||
|
});
|
||||||
|
|
||||||
|
api.interceptors.request.use(config => {
|
||||||
|
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default api;
|
||||||
47
client/src/pages/LoginForm.vue
Normal file
47
client/src/pages/LoginForm.vue
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import { onMounted, reactive } from "vue";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
|
import * as authApi from "../api/AuthApi";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const user = reactive({
|
||||||
|
username: "",
|
||||||
|
password: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
async function login(): Promise<void> {
|
||||||
|
|
||||||
|
const success: boolean = await authApi.login(user);
|
||||||
|
|
||||||
|
if(success) {
|
||||||
|
router.push("/users"); // redirect
|
||||||
|
} else {
|
||||||
|
// prompt try again
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Login</h2>
|
||||||
|
|
||||||
|
<form @submit.prevent="login">
|
||||||
|
<input v-model="user.username" placeholder="username" />
|
||||||
|
<input v-model="user.password" type="password" placeholder="password" />
|
||||||
|
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
50
client/src/pages/RegisterForm.vue
Normal file
50
client/src/pages/RegisterForm.vue
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import { onMounted, reactive } from "vue";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
|
import * as authApi from "../api/AuthApi";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const user = reactive({
|
||||||
|
username: "",
|
||||||
|
email: "",
|
||||||
|
password: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
async function register(): Promise<void> {
|
||||||
|
|
||||||
|
const success: boolean = await authApi.register(user);
|
||||||
|
|
||||||
|
if(success) {
|
||||||
|
router.push("/login"); // redirect
|
||||||
|
} else {
|
||||||
|
// prompt try again
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Register</h2>
|
||||||
|
|
||||||
|
<form @submit.prevent="register">
|
||||||
|
<input v-model="user.username" placeholder="username" />
|
||||||
|
<input v-model="user.email" placeholder="email" />
|
||||||
|
<input v-model="user.password" placeholder="password" />
|
||||||
|
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user