Implement token refreshing
This commit is contained in:
Generated
+8
@@ -528,6 +528,14 @@
|
|||||||
"is-buffer": "^2.0.2"
|
"is-buffer": "^2.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"axios-auth-refresh": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-1.0.7.tgz",
|
||||||
|
"integrity": "sha512-TQl1tF+MY+iDG93WpiqcnwGb1lvdJLKzi0IN/7hBkYFlpOC6xv4S+cW3QHZOBjKpFWRWqHg9fXd/PDsCvJ3uLA==",
|
||||||
|
"requires": {
|
||||||
|
"axios": "^0.18.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"babel-code-frame": {
|
"babel-code-frame": {
|
||||||
"version": "6.26.0",
|
"version": "6.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fancyapps/fancybox": "^3.5.7",
|
"@fancyapps/fancybox": "^3.5.7",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
|
"axios-auth-refresh": "^1.0.7",
|
||||||
"bootstrap-sass": "^3.4.1",
|
"bootstrap-sass": "^3.4.1",
|
||||||
"bourbon": "^4.3.2",
|
"bourbon": "^4.3.2",
|
||||||
"cookieconsent": "^3.1.0",
|
"cookieconsent": "^3.1.0",
|
||||||
|
|||||||
@@ -1,77 +1,26 @@
|
|||||||
// See https://www.techynovice.com/setting-up-JWT-token-refresh-mechanism-with-axios/
|
import axios from 'axios'
|
||||||
|
import createAuthRefreshInterceptor from 'axios-auth-refresh'
|
||||||
|
|
||||||
import axios from 'axios';
|
const authenticatedClient = axios.create();
|
||||||
|
|
||||||
const authenticatedClient = axios.create({
|
const getAccessToken = () => {
|
||||||
headers: {
|
return sessionStorage.getItem('token');
|
||||||
'Authentication': 'Bearer ' + sessionStorage.getItem('token')
|
};
|
||||||
}
|
|
||||||
|
authenticatedClient.interceptors.request.use(request => {
|
||||||
|
request.headers['Authorization'] = 'Bearer ' + getAccessToken();
|
||||||
|
return request;
|
||||||
});
|
});
|
||||||
|
|
||||||
authenticatedClient.interceptors.response.use(
|
const refreshAuth = failedRequest => axios.post('/api/token_refresh', {
|
||||||
response => response,
|
refresh_token: sessionStorage.getItem('refreshToken')
|
||||||
error => {
|
}).then(response => {
|
||||||
const errorResponse = error.response;
|
sessionStorage.setItem('token', response.data.token);
|
||||||
if (isTokenExpiredError(errorResponse)) {
|
sessionStorage.setItem('refreshToken', response.data.refresh_token);
|
||||||
return resetTokenAndReattemptRequest(error)
|
failedRequest.response.config.headers['Authorization'] = 'Bearer ' + response.data.token;
|
||||||
}
|
return Promise.resolve();
|
||||||
return Promise.reject(error)
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
function isTokenExpiredError (errorResponse) {
|
createAuthRefreshInterceptor(authenticatedClient, refreshAuth);
|
||||||
if (errorResponse.config.code !== 401) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorResponse.message.match(/expired/);
|
export default authenticatedClient
|
||||||
}
|
|
||||||
|
|
||||||
let isAlreadyFetchingAccessToken = false;
|
|
||||||
let subscribers = [];
|
|
||||||
|
|
||||||
async function resetTokenAndReattemptRequest (error) {
|
|
||||||
try {
|
|
||||||
const { response: errorResponse } = error;
|
|
||||||
const refreshToken = await getRefreshToken();
|
|
||||||
if (!refreshToken) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
const retryOriginalRequest = new Promise(resolve => {
|
|
||||||
addSubscriber(authToken => {
|
|
||||||
errorResponse.config.headers.Authorization = 'Bearer ' + authToken;
|
|
||||||
resolve(axios(errorResponse.config));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (!isAlreadyFetchingAccessToken) {
|
|
||||||
isAlreadyFetchingAccessToken = true;
|
|
||||||
axios({
|
|
||||||
method: 'post',
|
|
||||||
url: `<YOUR TOKEN REFREH ENDPOINT>`,
|
|
||||||
data: {
|
|
||||||
refresh_token: refreshToken
|
|
||||||
}
|
|
||||||
}).then(response => {
|
|
||||||
if (!response.data) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
const newToken = response.data.refresh_token;
|
|
||||||
saveRefreshToken(newToken);
|
|
||||||
isAlreadyFetchingAccessToken = false;
|
|
||||||
onAccessTokenFetched(newToken);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return retryOriginalRequest;
|
|
||||||
} catch (err) {
|
|
||||||
return Promise.reject(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onAccessTokenFetched(access_token) {
|
|
||||||
subscribers.forEach(callback => callback(access_token));
|
|
||||||
subscribers = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function addSubscriber(callback) {
|
|
||||||
subscribers.push(callback);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -65,10 +65,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from 'vuex'
|
||||||
import axios from 'axios'
|
|
||||||
import flatpickr from 'flatpickr'
|
import flatpickr from 'flatpickr'
|
||||||
import { German } from 'flatpickr/dist/l10n/de'
|
import { German } from 'flatpickr/dist/l10n/de'
|
||||||
import FormGroup from './components/FormGroup';
|
import FormGroup from './components/FormGroup'
|
||||||
|
import authenticatedClient from "../api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
...mapMutations(['alert', 'beginLoading', 'endLoading']),
|
...mapMutations(['alert', 'beginLoading', 'endLoading']),
|
||||||
loadFormOptions () {
|
loadFormOptions () {
|
||||||
this.beginLoading();
|
this.beginLoading();
|
||||||
return axios({
|
return authenticatedClient({
|
||||||
url: '/api/countries',
|
url: '/api/countries',
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
this.countries = response.data
|
this.countries = response.data
|
||||||
|
|||||||
@@ -62,7 +62,6 @@
|
|||||||
...mapGetters(['isLoggedIn', 'isTeamer'])
|
...mapGetters(['isLoggedIn', 'isTeamer'])
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.$store.commit('initSession');
|
|
||||||
if (this.isLoggedIn) {
|
if (this.isLoggedIn) {
|
||||||
this.$router.push({ name: 'address' })
|
this.$router.push({ name: 'address' })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from 'vuex'
|
||||||
import axios from 'axios'
|
import authenticatedClient from '../api'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data () {
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
created () {
|
created () {
|
||||||
this.beginLoading();
|
this.beginLoading();
|
||||||
|
|
||||||
return this.getClient().get('/api/crm-selections')
|
return authenticatedClient.get('/api/crm-selections')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.crmData = response.data
|
this.crmData = response.data
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@@ -71,17 +71,10 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(['beginLoading', 'endLoading', 'alert']),
|
...mapMutations(['beginLoading', 'endLoading', 'alert']),
|
||||||
getClient () {
|
|
||||||
return axios.create({
|
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer ' + this.authToken
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
save () {
|
save () {
|
||||||
this.beginLoading();
|
this.beginLoading();
|
||||||
|
|
||||||
return this.getClient().put('/api/crm-selections', this.crmData)
|
return authenticatedClient.put('/api/crm-selections', this.crmData)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.alert({
|
this.alert({
|
||||||
message: 'Die Änderungen wurden gespeichert',
|
message: 'Die Änderungen wurden gespeichert',
|
||||||
@@ -112,7 +105,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['loading', 'authToken'])
|
...mapState(['loading'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from 'vuex'
|
||||||
import axios from 'axios'
|
import authenticatedClient from "../api";
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import 'dayjs/locale/de'
|
import 'dayjs/locale/de'
|
||||||
|
|
||||||
@@ -63,13 +63,7 @@
|
|||||||
created () {
|
created () {
|
||||||
this.beginLoading();
|
this.beginLoading();
|
||||||
|
|
||||||
const client = axios.create({
|
return authenticatedClient.get('/api/events')
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer ' + this.authToken
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return client.get('/api/events')
|
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.events = response.data;
|
this.events = response.data;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@@ -94,7 +88,7 @@
|
|||||||
+ '/api/events/'
|
+ '/api/events/'
|
||||||
+ event.id
|
+ event.id
|
||||||
+ '/' + type + '?token='
|
+ '/' + type + '?token='
|
||||||
+ this.authToken;
|
+ sessionStorage.getItem('token');
|
||||||
},
|
},
|
||||||
calculateBalance (event) {
|
calculateBalance (event) {
|
||||||
if (!event.preis || !event.zahlung) {
|
if (!event.preis || !event.zahlung) {
|
||||||
@@ -111,7 +105,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['config', 'loading', 'authToken'])
|
...mapState(['config', 'loading'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from 'vuex'
|
||||||
import axios from 'axios'
|
import authenticatedClient from "../api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
@@ -32,13 +32,7 @@
|
|||||||
|
|
||||||
this.beginLoading();
|
this.beginLoading();
|
||||||
|
|
||||||
const client = axios.create({
|
return authenticatedClient.put('/api/newsletter', data)
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer ' + this.authToken
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return client.put('/api/newsletter', data)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.alert({
|
this.alert({
|
||||||
message: 'Die Änderungen wurden gespeichert',
|
message: 'Die Änderungen wurden gespeichert',
|
||||||
@@ -56,7 +50,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['loading', 'userData', 'authToken']),
|
...mapState(['loading', 'userData']),
|
||||||
statusMessage () {
|
statusMessage () {
|
||||||
let message = 'Du bist aktuell';
|
let message = 'Du bist aktuell';
|
||||||
message += this.userData.newsletter ? ' ' : ' <strong>nicht</strong> ';
|
message += this.userData.newsletter ? ' ' : ' <strong>nicht</strong> ';
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from 'vuex'
|
||||||
import axios from 'axios'
|
import authenticatedClient from "../api";
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import 'dayjs/locale/de'
|
import 'dayjs/locale/de'
|
||||||
import FormGroup from './components/FormGroup';
|
import FormGroup from './components/FormGroup';
|
||||||
@@ -107,13 +107,6 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(['beginLoading', 'endLoading', 'alert']),
|
...mapMutations(['beginLoading', 'endLoading', 'alert']),
|
||||||
getClient () {
|
|
||||||
return axios.create({
|
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer ' + this.authToken
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
save () {
|
save () {
|
||||||
const data = {
|
const data = {
|
||||||
abilities: this.userData.abilities,
|
abilities: this.userData.abilities,
|
||||||
@@ -128,7 +121,7 @@
|
|||||||
|
|
||||||
this.beginLoading();
|
this.beginLoading();
|
||||||
|
|
||||||
return this.getClient().put('/api/teamer-data', data)
|
return authenticatedClient.put('/api/teamer-data', data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.alert({
|
this.alert({
|
||||||
message: 'Die Änderungen wurden gespeichert',
|
message: 'Die Änderungen wurden gespeichert',
|
||||||
@@ -147,7 +140,7 @@
|
|||||||
created () {
|
created () {
|
||||||
this.beginLoading();
|
this.beginLoading();
|
||||||
|
|
||||||
return this.getClient().get('/api/teamer-data')
|
return authenticatedClient.get('/api/teamer-data')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.abilities = response.data.abilities;
|
this.abilities = response.data.abilities;
|
||||||
this.timeFrames = response.data.timeFrames;
|
this.timeFrames = response.data.timeFrames;
|
||||||
@@ -158,7 +151,7 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['userData', 'loading', 'authToken'])
|
...mapState(['userData', 'loading'])
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
period (timeFrame) {
|
period (timeFrame) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import authenticatedClient from "../api";
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ export default new Vuex.Store({
|
|||||||
config: {},
|
config: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
authToken: null,
|
authToken: null,
|
||||||
|
refreshToken: null,
|
||||||
userData: defaultUserData,
|
userData: defaultUserData,
|
||||||
alert: {
|
alert: {
|
||||||
message: '',
|
message: '',
|
||||||
@@ -57,14 +59,18 @@ export default new Vuex.Store({
|
|||||||
data.watchList = [...state.userData.watchList, ...data.watchList];
|
data.watchList = [...state.userData.watchList, ...data.watchList];
|
||||||
state.userData = data;
|
state.userData = data;
|
||||||
},
|
},
|
||||||
login(state, token) {
|
login(state, data) {
|
||||||
state.authToken = token;
|
state.authToken = data.token;
|
||||||
sessionStorage.setItem('token', token);
|
state.refreshToken = data.refresh_token;
|
||||||
|
sessionStorage.setItem('token', data.token);
|
||||||
|
sessionStorage.setItem('refreshToken', data.refresh_token);
|
||||||
},
|
},
|
||||||
logout(state) {
|
logout(state) {
|
||||||
state.authToken = null;
|
|
||||||
state.userData = defaultUserData;
|
state.userData = defaultUserData;
|
||||||
|
state.authToken = null;
|
||||||
|
state.refreshToken = null;
|
||||||
sessionStorage.removeItem('token');
|
sessionStorage.removeItem('token');
|
||||||
|
sessionStorage.removeItem('refreshToken');
|
||||||
sessionStorage.removeItem('watchlist');
|
sessionStorage.removeItem('watchlist');
|
||||||
},
|
},
|
||||||
alert(state, payload) {
|
alert(state, payload) {
|
||||||
@@ -97,7 +103,7 @@ export default new Vuex.Store({
|
|||||||
},
|
},
|
||||||
withCredentials: true
|
withCredentials: true
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
commit('login', response.data.token);
|
commit('login', response.data);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
commit('logout');
|
commit('logout');
|
||||||
commit('alert', {
|
commit('alert', {
|
||||||
@@ -109,14 +115,10 @@ export default new Vuex.Store({
|
|||||||
commit('endLoading');
|
commit('endLoading');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
logout({commit, state}) {
|
logout({commit}) {
|
||||||
commit('beginLoading');
|
commit('beginLoading');
|
||||||
const client = axios.create({
|
|
||||||
headers: {
|
return authenticatedClient({
|
||||||
'Authorization': 'Bearer ' + state.authToken,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return client({
|
|
||||||
url: '/api/logout'
|
url: '/api/logout'
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -164,13 +166,7 @@ export default new Vuex.Store({
|
|||||||
loadAddress({commit, state}) {
|
loadAddress({commit, state}) {
|
||||||
commit('beginLoading');
|
commit('beginLoading');
|
||||||
|
|
||||||
const client = axios.create({
|
return authenticatedClient.get('/api/address')
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer ' + state.authToken,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return client.get('/api/address')
|
|
||||||
.then(response => {
|
.then(response => {
|
||||||
commit('setUserData', response.data);
|
commit('setUserData', response.data);
|
||||||
if (response.data.watchlist) {
|
if (response.data.watchlist) {
|
||||||
@@ -188,13 +184,7 @@ export default new Vuex.Store({
|
|||||||
saveAddress({commit, state}, data) {
|
saveAddress({commit, state}, data) {
|
||||||
commit('beginLoading');
|
commit('beginLoading');
|
||||||
|
|
||||||
const client = axios.create({
|
return authenticatedClient.put('/api/address', data)
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer ' + state.authToken,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return client.put('/api/address', data)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
commit('alert', {
|
commit('alert', {
|
||||||
message: 'Die Änderungen wurden gespeichert',
|
message: 'Die Änderungen wurden gespeichert',
|
||||||
@@ -217,7 +207,7 @@ export default new Vuex.Store({
|
|||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
watchlistCount: state => state.userData.watchList.length,
|
watchlistCount: state => state.userData.watchList.length,
|
||||||
onWatchlist: (state) => (uid) => state.userData.watchList.indexOf(uid) !== -1,
|
onWatchlist: state => uid => state.userData.watchList.indexOf(uid) !== -1,
|
||||||
isLoggedIn: state => !!state.authToken,
|
isLoggedIn: state => !!state.authToken,
|
||||||
isTeamer: state => !!state.userData.isTeamer
|
isTeamer: state => !!state.userData.isTeamer
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user