add make login page functional using federation layer and enforce login in router
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
j3d1 2024-04-08 20:58:44 +02:00
parent 4bb75c095e
commit a10eb089b4
5 changed files with 111 additions and 29 deletions

View file

@ -6,6 +6,11 @@
<a class="sidebar-toggle d-flex" @click="toggleSidebar"> <a class="sidebar-toggle d-flex" @click="toggleSidebar">
<i class="hamburger align-self-center"></i> <i class="hamburger align-self-center"></i>
</a> </a>
<div class="navbar-collapse collapse">
<ul class="navbar-nav navbar-align">
<UserDropdown/>
</ul>
</div>
</nav> </nav>
<slot></slot> <slot></slot>
<Footer/> <Footer/>
@ -14,12 +19,15 @@
</template> </template>
<script> <script>
/* global closeAllDropdowns */
import Footer from "@/components/Footer.vue"; import Footer from "@/components/Footer.vue";
import Sidebar from "@/components/Sidebar.vue"; import Sidebar from "@/components/Sidebar.vue";
import UserDropdown from "@/components/UserDropdown.vue";
export default { export default {
name: 'BaseLayout', name: 'BaseLayout',
components: { components: {
UserDropdown,
Footer, Footer,
Sidebar Sidebar
}, },
@ -68,6 +76,10 @@ export default {
box-shadow: 0 0 2rem var(--bs-shadow) box-shadow: 0 0 2rem var(--bs-shadow)
} }
.navbar-align {
margin-left: auto;
}
.navbar-bg { .navbar-bg {
background: var(--bs-white); background: var(--bs-white);
} }

View file

@ -0,0 +1,47 @@
<template>
<li class="nav-item dropdown">
<a class="nav-icon dropdown-toggle d-inline-block d-sm-none" href="#" @click="toggleDropdown">
<i class="align-middle" data-feather="settings"></i>
<b-icon-person class="bi-valign-middle"></b-icon-person>
</a>
<a class="nav-link dropdown-toggle d-none d-sm-inline-block" href="#" @click="toggleDropdown">
<span class="text-dark">
{{ username }}
</span>
</a>
<div class="dropdown-menu dropdown-menu-right" id="userDropdown">
<a class="dropdown-item" href="#" @click="logout"> Log out</a>
</div>
</li>
</template>
<script>
import * as BIcons from 'bootstrap-icons-vue';
import {mapMutations, mapState} from "vuex";
export default {
name: "UserDropdown",
components: {
...BIcons
},
methods: {
...mapMutations(['logout']),
toggleDropdown() {
closeAllDropdowns();
document.getElementById("userDropdown").classList.toggle("show");
}
},
computed: {
...mapState(['user']),
username() {
return this.user;
},
}
}
</script>
<style scoped>
</style>

View file

@ -2,6 +2,7 @@ import {createRouter, createWebHistory} from 'vue-router'
import Index from '@/views/Index.vue'; import Index from '@/views/Index.vue';
import Login from '@/views/Login.vue'; import Login from '@/views/Login.vue';
import Register from '@/views/Register.vue'; import Register from '@/views/Register.vue';
import store from '@/store';
const routes = [ const routes = [
@ -20,7 +21,7 @@ const router = createRouter({
router.beforeEach((to/*, from*/) => { router.beforeEach((to/*, from*/) => {
// instead of having to check every route record with // instead of having to check every route record with
// to.matched.some(record => record.meta.requiresAuth) // to.matched.some(record => record.meta.requiresAuth)
if (to.meta.requiresAuth && false) { if (to.meta.requiresAuth && !store.getters.isLoggedIn) {
// this route requires auth, check if logged in // this route requires auth, check if logged in
// if not, redirect to login page. // if not, redirect to login page.
console.log("Not logged in, redirecting to login page") console.log("Not logged in, redirecting to login page")

View file

@ -24,7 +24,9 @@
<label class="form-label">Username</label> <label class="form-label">Username</label>
<input class="form-control form-control-lg" type="text" <input class="form-control form-control-lg" type="text"
name="username" placeholder="Enter your username" name="username" placeholder="Enter your username"
:class="errors.username?['is-invalid']:[]"
v-model="username"/> v-model="username"/>
<div class="invalid-feedback">{{ errors.username }}</div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Password</label> <label class="form-label">Password</label>
@ -65,6 +67,7 @@
</template> </template>
<script> <script>
import {mapActions, mapMutations} from 'vuex';
import router from "@/router"; import router from "@/router";
export default { export default {
@ -74,15 +77,15 @@ export default {
msg: 'Welcome to ' + location.hostname, msg: 'Welcome to ' + location.hostname,
username: '', username: '',
password: '', password: '',
remember: false remember: false,
errors: {
username: '',
}
} }
}, },
methods: { methods: {
setRemember(remember) { ...mapActions(['login']),
}, ...mapMutations(['setRemember']),
login(data) {
return true;
},
async do_login(e) { async do_login(e) {
e.preventDefault(); e.preventDefault();
if (await this.login({username: this.username, password: this.password, remember: this.remember})) { if (await this.login({username: this.username, password: this.password, remember: this.remember})) {
@ -92,11 +95,24 @@ export default {
await router.push({path: '/'}); await router.push({path: '/'});
} }
} else { } else {
if (!this.username.includes('@')) {
this.errors.username = 'Username should be in the form of user@domain';
}
this.msg = 'Invalid username or password'; this.msg = 'Invalid username or password';
} }
}, },
},
mounted() {
if (this.$route.query.redirect) {
this.msg = 'You must be logged in to access that page';
}
const user = localStorage.getItem('user');
if (user) {
this.username = user;
}
} }
} }
</script> </script>

View file

@ -44,6 +44,7 @@
<div :class="errors.email?['mb-3','is-invalid']:['mb-3']"> <div :class="errors.email?['mb-3','is-invalid']:['mb-3']">
<label class="form-label">Email</label> <label class="form-label">Email</label>
<input class="form-control form-control-lg" type="email" <input class="form-control form-control-lg" type="email"
:class="errors.email?['is-invalid']:[]"
v-model="form.email" placeholder="Enter your email"/> v-model="form.email" placeholder="Enter your email"/>
<div class="invalid-feedback">{{ errors.email }}</div> <div class="invalid-feedback">{{ errors.email }}</div>
</div> </div>
@ -51,6 +52,7 @@
<div :class="errors.password?['mb-3','is-invalid']:['mb-3']"> <div :class="errors.password?['mb-3','is-invalid']:['mb-3']">
<label class="form-label">Password</label> <label class="form-label">Password</label>
<input class="form-control form-control-lg" type="password" <input class="form-control form-control-lg" type="password"
:class="errors.password?['is-invalid']:[]"
v-model="form.password" placeholder="Enter your password"/> v-model="form.password" placeholder="Enter your password"/>
<div class="invalid-feedback">{{ errors.password }}</div> <div class="invalid-feedback">{{ errors.password }}</div>
</div> </div>
@ -58,6 +60,7 @@
<div :class="errors.password2?['mb-3','is-invalid']:['mb-3']"> <div :class="errors.password2?['mb-3','is-invalid']:['mb-3']">
<label class="form-label">Password Check</label> <label class="form-label">Password Check</label>
<input class="form-control form-control-lg" type="password" <input class="form-control form-control-lg" type="password"
:class="errors.password2?['is-invalid']:[]"
v-model="password2" placeholder="Enter your password again"/> v-model="password2" placeholder="Enter your password again"/>
<div class="invalid-feedback">{{ errors.password2 }}</div> <div class="invalid-feedback">{{ errors.password2 }}</div>
</div> </div>
@ -86,6 +89,10 @@
</template> </template>
<script> <script>
import {mapActions} from 'vuex';
import {ServerSet, createNullAuth} from '../federation';
import NeighborsCache from '../neigbors';
export default { export default {
name: 'Register', name: 'Register',
data() { data() {
@ -109,6 +116,7 @@ export default {
} }
}, },
methods: { methods: {
...mapActions(['lookupServer']),
do_register() { do_register() {
console.log('do_register'); console.log('do_register');
console.log(this.form); console.log(this.form);
@ -118,36 +126,34 @@ export default {
} else { } else {
this.errors.password2 = null; this.errors.password2 = null;
} }
fetch('/auth/register/', { const user = this.form.username + '@' + this.form.domain;
method: 'POST', var unreachable = new NeighborsCache();
headers: { var nullAuth = createNullAuth({})
'Content-Type': 'application/json', this.lookupServer({username: user}).then(servers => new ServerSet(servers, unreachable))
}, .then(set => set.post(nullAuth, '/auth/register/', this.form))
body: JSON.stringify(this.form) .then(response => {
}) if (response.errors) {
.then(response => response.json()) console.error('Error:', response.errors);
.then(data => { this.errors = response.errors;
if (data.errors) {
console.error('Error:', data.errors);
this.errors = data.errors;
return; return;
} }
console.log('Success:', data); console.log('Success:', response);
this.msg = 'Success'; this.msg = 'Success';
localStorage.setItem('user', user);
this.$router.push('/login'); this.$router.push('/login');
}) })
.catch((error) => {
console.error('Error:', error);
this.msg = 'Error';
});
} }
}, },
mounted() { mounted() {
fetch('/api/domains/') try {
fetch('/local/domains')
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
this.domains = data; this.domains = data;
}); });
} catch (e) {
console.error('Error:', e);
}
} }
} }
</script> </script>