Skip to content

Commit

Permalink
WIP: Add authentication page (#88)
Browse files Browse the repository at this point in the history
* Add sign out functionality

* Add sign in and sign out functionality

* Slight refactoring

* Add redirection after signing in

* Update auth form

* Update remember me feature

* Add Remember me feature

* Update idleness interval

* Update authorization form
  • Loading branch information
blackst0ne authored Mar 16, 2018
1 parent b6028ab commit 6f79ab0
Show file tree
Hide file tree
Showing 17 changed files with 333 additions and 32 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"axios": "^0.16.2",
"bootstrap": "4.0.0-beta.2",
"chart.js": "^2.7.0",
"idle-vue": "^2.0.5",
"vue": "^2.4.2",
"vue-axios": "^2.0.2",
"vue-chartjs": "^2.8.7",
Expand Down
28 changes: 24 additions & 4 deletions src/components/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,35 @@
<router-link :to="{ name: 'Analytics' }" key="analytics">Аналитика</router-link>
</span>

<router-link to="events">
Войти
<i class="fa fa-long-arrow-right align-middle" aria-hidden="true" />
</router-link>
<span v-if="$store.getters.user.authorized">
<a href="javascript:void(0)" v-on:click="signOut" key="sign-out">
Выйти
<i class="fa fa-times"></i>
</a>
</span>
<span v-else>
<router-link :to="{ name: 'UserAuthorization' }" key="sign-in">
Войти
<i class="fa fa-long-arrow-right align-middle" aria-hidden="true" />
</router-link>
</span>
</b-col>
</b-row>
</header>
</template>

<script>
export default {
methods: {
signOut: function() {
this.$store.dispatch('signOut')
this.$router.go()
}
}
}
</script>


<style lang="scss" scoped>
@import '../assets/scss/global.scss';
Expand Down
2 changes: 1 addition & 1 deletion src/components/Events.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ require('moment/locale/ru')
import CountersHeader from '@/components/CountersHeader.vue'
import Filters from '@/components/Filters.vue'
import Spinner from 'vue-simple-spinner'
import { round } from '@/helpers.js'
import { round } from '@/helpers/math.js'
export default {
components: { CountersHeader, Filters, Spinner },
Expand Down
2 changes: 1 addition & 1 deletion src/components/event/LastEvents.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
const moment = require('moment')
require('moment/locale/ru')
import { round } from '@/helpers.js'
import { round } from '@/helpers/math.js'
export default {
props: ['event'],
Expand Down
2 changes: 1 addition & 1 deletion src/components/event/Settlements.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<script>
import Spinner from 'vue-simple-spinner'
import { convertMsk64 } from '@/map_functions.js'
import { round } from '@/helpers.js'
import { round } from '@/helpers/math.js'
export default {
components: { Spinner },
Expand Down
197 changes: 197 additions & 0 deletions src/components/users/Authorization.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
<template>
<div class="sign-in">
<b-row class="breadcrumbs" no-gutters>
<b-col cols="12">
<b-breadcrumb :items="breadcrumbs" />
</b-col>
</b-row>

<b-row>
<b-col cols="6" offset="3">
<div class="validation-error">{{ validationError }}</div>

<b-form class="sign-in-form"
ref="form"
:validated="form.validated"
novalidate>
<b-form-group>
<b-form-input type="email"
:disabled="form.fields.email.disabled"
:state="form.fields.email.state"
v-model="form.fields.email.value"
maxlength="150"
pattern="[^@\s]+@[^@\s]+\.[^@\s]+"
placeholder="Электронная почта"
required>
</b-form-input>
<b-form-invalid-feedback>{{ form.messages.email }}</b-form-invalid-feedback>
</b-form-group>

<b-form-group>
<b-form-input type="password"
:disabled="form.fields.password.disabled"
:state="form.fields.password.state"
v-model="form.fields.password.value"
placeholder="Пароль"
minlength="6"
maxlength="150"
required>
</b-form-input>
<b-form-invalid-feedback>{{ form.messages.password }}</b-form-invalid-feedback>
</b-form-group>
</b-form>

<b-form-group>
<b-form-checkbox v-model="form.fields.rememberMe.value">Запомнить меня</b-form-checkbox>

<router-link :to="{ name: 'UserResetPassword' }" key="reset-password" class="reset-password-link">
Сбросить пароль
</router-link>
</b-form-group>

<b-button type="submit"
variant="send-request"
:disabled="form.submitButtonDisabled"
v-on:click="onSubmit">
Войти
</b-button>

<div class="registration-block">
<router-link :to="{ name: 'UserRegistration' }" key="registration">
Зарегистрироваться
</router-link>
</div>
</b-col>
</b-row>
</div>
</template>

<script>
export default {
data() {
return {
breadcrumbs: [
{
text: 'Главная',
href: this.$router.resolve({ name: 'Mainpage' }).href
}, {
text: 'Вход',
active: true
}
],
form: {
fields: {
email: { value: '', disabled: false, state: null },
password: { value: '', disabled: false, state: null },
rememberMe: { value: '', disabled: false }
},
messages: {
email: 'Некорректная электронная почта',
password: 'Некорректный пароль'
},
submitButtonDisabled: false,
validated: false
},
redirectTo: '?',
validationError: ''
}
},
methods: {
enableFields: function() {
this.changeFieldsDisabledState(false)
},
changeFieldsDisabledState: function(state) {
Object.keys(this.form.fields).forEach(key => {
this.form.fields[key].disabled = state
})
this.form.submitButtonDisabled = state
},
disableFields: function() {
this.changeFieldsDisabledState(true)
},
onSubmit: function() {
this.form.validated = true
if (!this.$refs.form.checkValidity()) return
const payload = {
password: this.form.fields.password.value,
username: this.form.fields.email.value
}
this.disableFields()
this.$http.post(this.$root.$options.settings.api.endpointUserAuthorization, payload)
.then(response => {
this.$store.dispatch('authorizeUser', {
accessToken: response.data.access_token,
refreshToken: response.data.refresh_token,
rememberMe: this.form.fields.rememberMe.value
})
this.$router.push(this.redirectTo)
})
.catch(error => {
if (error.response) {
this.validationError = error.response.data.message
this.enableFields()
} else {
console.log(error)
}
})
}
},
beforeRouteEnter: (to, from, next) => {
next(vm => {
vm.redirectTo = from.path
})
}
}
</script>

<style lang="scss" scoped>
@import '../../assets/scss/global';
.breadcrumbs {
.breadcrumb {
background-color: transparent;
margin-top: 4%;
padding-left: 0;
padding-top: 0;
.active {
color: $color-gray-dark;
}
}
}
.validation-error {
color: red;
text-align: center;
}
.sign-in-form {
border-bottom: 1px solid $color-gray-light;
padding-bottom: 3%;
margin-bottom: 3%;
}
.btn {
width: 100%;
}
.btn-send-request {
background-color: $color-blue;
color: $color-white;
}
.reset-password-link {
float: right;
}
.registration-block {
padding-top: 3%;
text-align: center;
}
</style>
Empty file.
19 changes: 19 additions & 0 deletions src/helpers/axios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import store from '../store'
import axios from 'axios'

import ApiSettings from '../settings/api.js'

export function axiosSetAuthorizationHeaders() {
const apiToken = store.getters.user.accessToken

if (apiToken) {
const apiSettings = new ApiSettings()
const apiType = apiSettings.authorizationType

axios.defaults.headers.common['Authorization'] = `${apiType} ${apiToken}`
}
}

export function axiosRemoveAuthorizationHeaders() {
delete axios.defaults.headers.common['Authorization']
}
File renamed without changes.
17 changes: 9 additions & 8 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import router from './router'
import store from './store'
import axios from 'axios'
import VueAxios from 'vue-axios'
import IdleVue from 'idle-vue'

import ApiSettings from './settings/api.js'
import EventsSettings from './settings/events.js'
import StationsSettings from './settings/stations.js'
import { axiosSetAuthorizationHeaders } from './helpers/axios'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Expand All @@ -19,22 +21,21 @@ Vue.config.productionTip = false

Vue.use(VueAxios, axios)
Vue.use(BootstrapVue)
Vue.use(IdleVue, {
idleTime: 600000,
startAtIdle: true,
store
})

const apiSettings = new ApiSettings()

// Set axios authorization headers.
const apiToken = store.getters.user.token
const apiType = apiSettings.authorizationType

if (apiToken) axios.defaults.headers.common['Authorization'] = `${apiType} ${apiToken}`
axiosSetAuthorizationHeaders()

/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
settings: {
api: apiSettings,
api: new ApiSettings(),
events: EventsSettings,
stations: StationsSettings
},
Expand Down
10 changes: 8 additions & 2 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import Analytics from '@/components/Analytics'
import Event from '@/components/Event'
import Events from '@/components/Events'
import StaticPage from '@/components/StaticPage'
import UserAuthorization from '@/components/users/Authorization'
import UserEmailConfirmation from '@/components/users/Confirmation'
import UserAuthorization from '@/components/users/Authorization'
import UserRegistration from '@/components/users/Registration'
import UserResetPassword from '@/components/users/ResetPassword'

Vue.use(Router)

Expand All @@ -29,10 +30,15 @@ export default new Router({
component: UserEmailConfirmation
},
{
path: '/sign_in',
path: '/sign-in',
name: 'UserAuthorization',
component: UserAuthorization
},
{
path: '/reset-password',
name: 'UserResetPassword',
component: UserResetPassword
},
{
path: '/analytics',
name: 'Analytics',
Expand Down
1 change: 1 addition & 0 deletions src/settings/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Config {
this.endpointPurposesList = `${this.baseURL}/${this.version}/user/purposesList`
this.endpointStations = `${this.baseURL}/${this.version}/stations`
this.endpointSystemInfo = `${this.baseURL}/${this.version}/systemInfo`
this.endpointUserAuthorization = `https://oauth-client-test.geophystech.ru/token`
this.endpointUserRegistration = `${this.baseURL}/${this.version}/user/register`
}

Expand Down
Loading

0 comments on commit 6f79ab0

Please sign in to comment.