- added 2fa authentication during login. see resources/js/Pages/Auth/login.vue
All checks were successful
CI Pipeline / japa-tests (push) Successful in 1m2s
All checks were successful
CI Pipeline / japa-tests (push) Successful in 1m2s
- added validate() method inside app/Srvices/TwoFactorProvider.ts - added twoFactorChallenge() method inside app/Controllers/Http/Auth/AuthController.ts for logging in via 2fa-code
This commit is contained in:
parent
b2dce0259a
commit
f828ca4491
7 changed files with 233 additions and 84 deletions
|
@ -2,7 +2,7 @@
|
|||
// import { Head, Link, useForm, usePage } from '@inertiajs/inertia-vue3';
|
||||
import { Head, Link, useForm, usePage } from '@inertiajs/vue3';
|
||||
import { ComputedRef } from 'vue';
|
||||
import { mdiAccountKey, mdiPlus, mdiSquareEditOutline, mdiTrashCan, mdiAlertBoxOutline } from '@mdi/js';
|
||||
import { mdiAccountKey, mdiPlus, mdiSquareEditOutline, mdiAlertBoxOutline } from '@mdi/js';
|
||||
import { computed } from 'vue';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
|
|
|
@ -1,37 +1,7 @@
|
|||
<!-- <template>
|
||||
<div>
|
||||
<Link href="/app">Home</Link>
|
||||
<br />
|
||||
<h1>Login</h1>
|
||||
<Head>
|
||||
<title>About - My app</title>
|
||||
<meta
|
||||
head-key="description"
|
||||
name="description"
|
||||
content="This is a page specific description"
|
||||
/>
|
||||
</Head>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthLayout from '@/Layouts/Auth.vue';
|
||||
import LayoutGuest from '@/Layouts/LayoutGuest.vue';
|
||||
export default {
|
||||
layout: AuthLayout,
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup>
|
||||
// import { Head, Link } from '@inertiajs/vue3';
|
||||
import { Head, Link } from '@inertiajs/inertia-vue3'
|
||||
import FormField from '@/Components/FormField.vue';
|
||||
import FormControl from '@/Components/FormControl.vue';
|
||||
</script> -->
|
||||
|
||||
<template>
|
||||
<LayoutGuest>
|
||||
|
||||
<Head title="Login" />
|
||||
|
||||
<!-- <SectionFullScreen v-slot="{ cardClass }" :bg="'greenBlue'"> -->
|
||||
|
@ -40,8 +10,9 @@ import FormControl from '@/Components/FormControl.vue';
|
|||
<img src="/logo.svg" class="h-10 mr-4" alt="Windster Logo" />
|
||||
<!-- <span class="self-center text-2xl font-bold whitespace-nowrap">Tethys</span> -->
|
||||
</a>
|
||||
<!-- Card -->
|
||||
<CardBox :class="cardClass" form @submit.prevent="submit">
|
||||
|
||||
<CardBox v-if="isTwoFactorAuthNeeded == false" :class="cardClass" form
|
||||
@submit.prevent="submit">
|
||||
<FormValidationErrors v-bind:errors="errors" />
|
||||
|
||||
<NotificationBarInCard v-if="status" color="info">
|
||||
|
@ -49,18 +20,13 @@ import FormControl from '@/Components/FormControl.vue';
|
|||
</NotificationBarInCard>
|
||||
|
||||
<FormField label="Email" label-for="email" help="Please enter your email">
|
||||
<FormControl v-model="form.email" :icon="mdiAccount" id="email" autocomplete="email" type="email" required />
|
||||
<FormControl v-model="form.email" :icon="mdiAccount" id="email" autocomplete="email" type="email"
|
||||
required />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Password" label-for="password" help="Please enter your password">
|
||||
<FormControl
|
||||
v-model="form.password"
|
||||
:icon="mdiAsterisk"
|
||||
type="password"
|
||||
id="password"
|
||||
autocomplete="current-password"
|
||||
required
|
||||
/>
|
||||
<FormControl v-model="form.password" :icon="mdiAsterisk" type="password" id="password"
|
||||
autocomplete="current-password" required />
|
||||
</FormField>
|
||||
|
||||
<FormCheckRadioGroup v-model="form.remember" name="remember" :options="{ remember: 'Remember' }" />
|
||||
|
@ -79,36 +45,62 @@ import FormControl from '@/Components/FormControl.vue';
|
|||
<BaseDivider />
|
||||
|
||||
<!-- buttons -->
|
||||
<BaseLevel>
|
||||
<BaseButtons>
|
||||
<!-- <BaseButton type="submit" color="info" label="Login" :class="{ 'opacity-25': form.processing }"
|
||||
v-bind:disabled="form.processing" /> -->
|
||||
<button
|
||||
type="submit"
|
||||
v-bind:disabled="form.processing"
|
||||
:class="{ 'opacity-25': form.processing }"
|
||||
class="text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-base px-5 py-3 w-full sm:w-auto text-center"
|
||||
>
|
||||
Login to your account
|
||||
</button>
|
||||
<!-- <BaseButton v-if="canResetPassword" :route-name="route('password.request')" color="info" outline
|
||||
|
||||
<BaseButtons>
|
||||
<BaseButton type="submit" color="info" label=" Login to your account" :class="{ 'opacity-25': form.processing }"
|
||||
v-bind:disabled="form.processing" />
|
||||
<!-- <button type="submit" v-bind:disabled="form.processing" :class="{ 'opacity-25': form.processing }"
|
||||
class="text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-base px-5 py-3 w-full sm:w-auto text-center">
|
||||
Login to your account
|
||||
</button> -->
|
||||
<!-- <BaseButton v-if="canResetPassword" :route-name="route('password.request')" color="info" outline
|
||||
label="Remind" /> -->
|
||||
</BaseButtons>
|
||||
<!-- <Link :href="stardust.route('app.register.show')"> Register </Link> -->
|
||||
</BaseLevel>
|
||||
<div class="text-sm font-medium text-gray-500">
|
||||
</BaseButtons>
|
||||
<!-- <Link :href="stardust.route('app.register.show')"> Register </Link> -->
|
||||
|
||||
<!-- <div class="text-sm font-medium text-gray-500">
|
||||
Not registered? <a href="" class="text-teal-500 hover:underline">Create account</a>
|
||||
</div>
|
||||
</div> -->
|
||||
</CardBox>
|
||||
|
||||
|
||||
<CardBox v-else-if="isTwoFactorAuthNeeded" :icon="mdiTwoFactorAuthentication" :class="cardClass" form
|
||||
@submit.prevent="submitFa2Form">
|
||||
<FormField label="2FA Code" label-for="code" help="Please enter 2factor code">
|
||||
<FormControl v-model="fa2Form.code" :icon="mdiAccount" id="code" type="tel" required />
|
||||
</FormField>
|
||||
|
||||
<div v-if="flash && flash.message" class="flex flex-col mt-6 animate-fade-in">
|
||||
<div class="bg-yellow-500 border-l-4 border-orange-400 text-white p-4" role="alert">
|
||||
<p class="font-bold">Be Warned</p>
|
||||
<p>{{ flash.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<BaseDivider />
|
||||
|
||||
|
||||
<BaseButtons>
|
||||
<!-- <button type="submit" :icon="mdiContentSaveCheck" :disabled="fa2Form.processing"
|
||||
:class="{ 'opacity-25': fa2Form.processing }"
|
||||
class="text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-base px-5 py-3 w-full sm:w-auto text-center">
|
||||
Verify
|
||||
</button> -->
|
||||
<BaseButton type="submit" :icon="mdiContentSaveCheck" color="info" label=" Login to your account" :class="{ 'opacity-25': fa2Form.processing }"
|
||||
v-bind:disabled="fa2Form.processing" />
|
||||
</BaseButtons>
|
||||
<!-- <Link :href="stardust.route('app.register.show')"> Register </Link> -->
|
||||
|
||||
</CardBox>
|
||||
|
||||
</SectionFullScreen>
|
||||
</LayoutGuest>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useForm, Head } from '@inertiajs/vue3';
|
||||
import { Ref } from 'vue';
|
||||
import { Ref, ref } from 'vue';
|
||||
// import { Head, Link, useForm } from '@inertiajs/inertia-vue3';
|
||||
import { mdiAccount, mdiAsterisk } from '@mdi/js';
|
||||
import { mdiAccount, mdiAsterisk, mdiTwoFactorAuthentication, mdiContentSaveCheck, mdiLock } from '@mdi/js';
|
||||
import LayoutGuest from '@/Layouts/LayoutGuest.vue';
|
||||
import SectionFullScreen from '@/Components/SectionFullScreen.vue';
|
||||
import CardBox from '@/Components/CardBox.vue';
|
||||
|
@ -116,22 +108,55 @@ import FormCheckRadioGroup from '@/Components/FormCheckRadioGroup.vue';
|
|||
import FormField from '@/Components/FormField.vue';
|
||||
import FormControl from '@/Components/FormControl.vue';
|
||||
import BaseDivider from '@/Components/BaseDivider.vue';
|
||||
// import BaseButton from '@/Components/BaseButton.vue';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
import BaseButtons from '@/Components/BaseButtons.vue';
|
||||
import FormValidationErrors from '@/Components/FormValidationErrors.vue';
|
||||
import NotificationBarInCard from '@/Components/NotificationBarInCard.vue';
|
||||
import BaseLevel from '@/Components/BaseLevel.vue';
|
||||
|
||||
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
// import NotificationBar from '@/Components/NotificationBar.vue';
|
||||
import { computed } from 'vue';
|
||||
import { computed, watch } from 'vue';
|
||||
import { usePage } from '@inertiajs/vue3';
|
||||
// import axios from 'axios';
|
||||
// import { LoginState } from '@/Dataset';
|
||||
|
||||
// interface IErrorMessage {
|
||||
// [key: string]: Array<string>;
|
||||
// }
|
||||
const flash: Ref<any> = computed(() => {
|
||||
return usePage().props.flash;
|
||||
let test = usePage().props;
|
||||
return test.flash;
|
||||
});
|
||||
|
||||
const user_id: Ref<any> = computed(() => {
|
||||
let test = usePage().props;
|
||||
return test.user_id;
|
||||
});
|
||||
|
||||
const isTwoFactorAuthNeeded = ref(false);
|
||||
|
||||
// const user_id: ComputedRef<number> = computed(() => {
|
||||
// return usePage().props.flash.user_id as number;
|
||||
// });
|
||||
|
||||
|
||||
// const isTwoFactorAuthNeeded = computed(() => {
|
||||
// if (flash.new_user_id) {
|
||||
// return true;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
|
||||
watch(user_id, () => {
|
||||
if (user_id.value) {
|
||||
isTwoFactorAuthNeeded.value = true;
|
||||
} else {
|
||||
isTwoFactorAuthNeeded.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
defineProps({
|
||||
|
@ -146,11 +171,57 @@ defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
const form = useForm({
|
||||
// const { version } = usePage();
|
||||
|
||||
const form = useForm(() => ({
|
||||
email: '',
|
||||
password: '',
|
||||
remember: [],
|
||||
});
|
||||
}));
|
||||
|
||||
// const login = async (data): Promise<any | null> => {
|
||||
// try {
|
||||
// let resp = await axios.post(stardust.route('login.store'), data, {
|
||||
// headers: {
|
||||
// 'X-Inertia': true,
|
||||
// 'X-Inertia-Partial-Component': 'Users',
|
||||
// 'X-Inertia-Partial-Data': 'users',
|
||||
// 'X-Inertia-Version': version,
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Check if the response contains a redirect status
|
||||
// if (resp.data.component && resp.data.url) {
|
||||
// // Use Inertia.js to visit the specified component
|
||||
// router.visit(resp.data.url, resp.data.props);
|
||||
// } else {
|
||||
// // If it's not a redirect, reset the password field in the form
|
||||
// form.reset('password');
|
||||
// return resp.data;
|
||||
// }
|
||||
|
||||
// } catch (error) {
|
||||
// // Handle errors if any
|
||||
// console.error('Error during login:', error);
|
||||
// throw error;
|
||||
// }
|
||||
// };
|
||||
|
||||
// const submit = async () => {
|
||||
// // Transform the formData object
|
||||
// const formData = form.data();
|
||||
// const transformedData = {
|
||||
// ...formData,
|
||||
// remember: formData.remember && formData.remember.length ? 'on' : '',
|
||||
// };
|
||||
// const resp = await login(transformedData);
|
||||
// if (resp) {
|
||||
// if (resp.state == LoginState.STATE_VALIDATED) {
|
||||
// isTwoFactorAuthNeeded.value = true
|
||||
// }
|
||||
// fa2Form.login_id = resp.new_user_id;
|
||||
// }
|
||||
// };
|
||||
|
||||
const submit = async () => {
|
||||
await form
|
||||
|
@ -164,4 +235,26 @@ const submit = async () => {
|
|||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const fa2Form = useForm(() => ({
|
||||
code: '',
|
||||
remember: [],
|
||||
login_id: ''
|
||||
}));
|
||||
const submitFa2Form = async () => {
|
||||
await fa2Form
|
||||
.transform((data) => ({
|
||||
...data,
|
||||
remember: fa2Form.remember && fa2Form.remember.length ? 'on' : '',
|
||||
login_id: user_id.value
|
||||
}))
|
||||
.post(stardust.route('login.twoFactorChallenge'), {
|
||||
onFinish: () => {
|
||||
fa2Form.reset('code');
|
||||
fa2Form.reset('login_id');
|
||||
// form.reset('password');
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue