mirror of
https://git.meshkee.com/cssd/cssd-front.git
synced 2026-10-12 05:23:25 +03:30
fix
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { TokenService } from '@/services'
|
||||
|
||||
const $hasRole = function (roles) {
|
||||
if (TokenService.getToken()) {
|
||||
roles = roles.split('|');
|
||||
for (const role of roles) {
|
||||
if (TokenService.getInfo().roles && Array.isArray(TokenService.getInfo().roles) && TokenService.getInfo().roles.includes(role)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
$hasRole
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import qs from 'qs';
|
||||
|
||||
const TOKEN_KEY = 'access_token'
|
||||
const REFRESH_TOKEN_KEY = 'refresh_token'
|
||||
const INFO = 'info'
|
||||
/**
|
||||
* Manage the how Access Tokens are being stored and retreived from storage.
|
||||
*
|
||||
* Current implementation stores to localStorage. Local Storage should always be
|
||||
* accessed through this instace.
|
||||
**/
|
||||
const TokenService = {
|
||||
getToken() {
|
||||
return localStorage.getItem(TOKEN_KEY)
|
||||
},
|
||||
|
||||
saveToken(accessToken = null) {
|
||||
localStorage.setItem(TOKEN_KEY, accessToken)
|
||||
},
|
||||
|
||||
removeToken() {
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
},
|
||||
|
||||
getRefreshToken() {
|
||||
return localStorage.getItem(REFRESH_TOKEN_KEY)
|
||||
},
|
||||
|
||||
saveRefreshToken(refreshToken = null) {
|
||||
localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken)
|
||||
},
|
||||
|
||||
removeRefreshToken() {
|
||||
localStorage.removeItem(REFRESH_TOKEN_KEY)
|
||||
},
|
||||
|
||||
getInfo() {
|
||||
return qs.parse(localStorage.getItem(INFO))
|
||||
},
|
||||
|
||||
saveInfo(info = null) {
|
||||
info = qs.stringify(info);
|
||||
localStorage.setItem(INFO, info)
|
||||
},
|
||||
|
||||
removeInfo() {
|
||||
localStorage.removeItem(INFO)
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
export { TokenService }
|
||||
@@ -0,0 +1,127 @@
|
||||
import { ApiService } from "../global/api.service";
|
||||
import { TokenService } from "./storage.service";
|
||||
import { urls } from "@/config/urls";
|
||||
import toast from "../global/toast.service";
|
||||
|
||||
class AuthenticationError extends Error {
|
||||
constructor(errorCode, message) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
this.message = message;
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
}
|
||||
|
||||
const UserService = {
|
||||
/**
|
||||
* Login the user and store the access token to TokenService.
|
||||
*
|
||||
* @returns access_token
|
||||
* @throws AuthenticationError
|
||||
**/
|
||||
login: async function(cell_number, password) {
|
||||
const requestData = {
|
||||
method: "post",
|
||||
url: urls.login,
|
||||
data: {
|
||||
cell_number,
|
||||
password,
|
||||
grant_type: "password"
|
||||
},
|
||||
auth: {
|
||||
username: process.env.MIX_APP_CLIENT_ID,
|
||||
password: process.env.MIX_APP_CLIENT_SECRET
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await ApiService.customRequest(requestData);
|
||||
TokenService.saveToken(response.data.access_token);
|
||||
TokenService.saveRefreshToken(response.data.refresh_token);
|
||||
ApiService.setAuthHeader();
|
||||
|
||||
// NOTE: We haven't covered this yet in our ApiService
|
||||
// but don't worry about this just yet - I'll come back to it later
|
||||
ApiService.mount401Interceptor();
|
||||
return response;
|
||||
} catch (error) {
|
||||
toast.error('Username Or Password Is Incorrect', 'Error');
|
||||
throw new AuthenticationError(
|
||||
error.response.status,
|
||||
error.response.data.detail
|
||||
);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Refresh the access token.
|
||||
**/
|
||||
refreshToken: async function() {
|
||||
const refreshToken = TokenService.getRefreshToken();
|
||||
|
||||
const requestData = {
|
||||
method: "post",
|
||||
url: urls.login,
|
||||
data: {
|
||||
grant_type: "refresh_token",
|
||||
refresh_token: refreshToken
|
||||
},
|
||||
auth: {
|
||||
username: process.env.MIX_APP_CLIENT_ID,
|
||||
password: process.env.MIX_APP_CLIENT_SECRET
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await ApiService.customRequest(requestData);
|
||||
|
||||
TokenService.saveToken(response.data.access_token);
|
||||
TokenService.saveRefreshToken(response.data.refresh_token);
|
||||
// Update the header in ApiService
|
||||
ApiService.setAuthHeader();
|
||||
|
||||
return response.data.access_token;
|
||||
} catch (error) {
|
||||
throw new AuthenticationError(
|
||||
error.response.status,
|
||||
error.response.data.detail
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Logout the current user by removing the token from storage.
|
||||
*
|
||||
* Will also remove `Authorization Bearer <token>` header from future requests.
|
||||
**/
|
||||
logout: async function() {
|
||||
try {
|
||||
await ApiService.post(urls.logout);
|
||||
// Remove the token and remove Authorization header from Api Service as well
|
||||
TokenService.removeToken();
|
||||
TokenService.removeRefreshToken();
|
||||
TokenService.removeInfo();
|
||||
ApiService.removeAuthHeader();
|
||||
|
||||
// NOTE: Again, we'll cover the 401 Interceptor a bit later.
|
||||
ApiService.unmount401Interceptor();
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Get Information the current user ;
|
||||
*
|
||||
* Will also Register in Store;
|
||||
**/
|
||||
getInfo: async function() {
|
||||
const response = await ApiService.get(urls.getInfo);
|
||||
TokenService.saveInfo(response.data.data);
|
||||
return response.data.data;
|
||||
}
|
||||
};
|
||||
|
||||
export default UserService;
|
||||
|
||||
export { UserService, AuthenticationError };
|
||||
@@ -0,0 +1,100 @@
|
||||
import axios from 'axios'
|
||||
import { TokenService } from '../auth/storage.service'
|
||||
import store from '@/store'
|
||||
|
||||
const ApiService = {
|
||||
|
||||
init(baseURL) {
|
||||
axios.defaults.baseURL = baseURL;
|
||||
},
|
||||
|
||||
setHeader() {
|
||||
axios.defaults.headers.common["Accept"] = `application/json`;
|
||||
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
},
|
||||
|
||||
setAuthHeader() {
|
||||
axios.defaults.headers.common["Authorization"] = `Bearer ${TokenService.getToken()}`;
|
||||
},
|
||||
|
||||
removeAuthHeader() {
|
||||
axios.defaults.headers.common["Authorization"] = null;
|
||||
},
|
||||
|
||||
get(resource) {
|
||||
return axios.get(resource)
|
||||
},
|
||||
|
||||
post(resource, data) {
|
||||
return axios.post(resource, data)
|
||||
},
|
||||
|
||||
put(resource, data) {
|
||||
data['_method'] = 'put';
|
||||
return axios.post(resource, data)
|
||||
},
|
||||
|
||||
delete(resource) {
|
||||
let data = {'_method': 'delete'};
|
||||
return axios.post(resource, data)
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform a custom Axios request.
|
||||
*
|
||||
* data is an object containing the following properties:
|
||||
* - method
|
||||
* - url
|
||||
* - data ... request payload
|
||||
* - auth (optional)
|
||||
* - username
|
||||
* - password
|
||||
**/
|
||||
customRequest(data) {
|
||||
return axios(data);
|
||||
},
|
||||
|
||||
_401interceptor: null,
|
||||
|
||||
mount401Interceptor() {
|
||||
this._401interceptor = axios.interceptors.response.use(
|
||||
(response) => {
|
||||
return response
|
||||
},
|
||||
async (error) => {
|
||||
if (error.request.status == 401) {
|
||||
if (error.config.url.includes('login')) {
|
||||
// Refresh token has failed. Logout the user
|
||||
store.dispatch('auth/logout');
|
||||
throw error;
|
||||
} else {
|
||||
// Refresh the access token
|
||||
try{
|
||||
await store.dispatch('refreshToken')
|
||||
// Retry the original request
|
||||
return this.customRequest({
|
||||
method: error.config.method,
|
||||
url: error.config.url,
|
||||
data: error.config.data
|
||||
})
|
||||
} catch (e) {
|
||||
// Refresh has failed - reject the original request
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If error was not 401 just reject as is
|
||||
throw error
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
unmount401Interceptor() {
|
||||
// Eject the interceptor
|
||||
axios.interceptors.response.eject(this._401interceptor)
|
||||
}
|
||||
}
|
||||
|
||||
export default ApiService
|
||||
export { ApiService }
|
||||
@@ -0,0 +1,49 @@
|
||||
import axios from "axios";
|
||||
import toast from "./toast.service";
|
||||
import {TokenService, ApiService} from '@/services';
|
||||
import store from "@/store"
|
||||
import router from '@/router'
|
||||
function errorResponseHandler(error) {
|
||||
|
||||
// check for errorHandle config
|
||||
if (
|
||||
error.config.hasOwnProperty("errorHandle") &&
|
||||
error.config.errorHandle === false
|
||||
) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
// if has response show the error
|
||||
if (error.response) {
|
||||
if(typeof error.response.data.errors !== 'undefined') {
|
||||
for (const key in error.response.data.errors) {
|
||||
if (error.response.data.errors.hasOwnProperty(key)) {
|
||||
let title = (error.response.data.title) ? error.response.data.title : undefined;
|
||||
toast.error(error.response.data.errors[key], title);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(error.response.status == 401) {
|
||||
TokenService.removeToken();
|
||||
TokenService.removeRefreshToken();
|
||||
TokenService.removeInfo();
|
||||
ApiService.removeAuthHeader();
|
||||
store.commit('auth/logoutSuccess', {}, {root: true})
|
||||
router.push({ name: `Dashboard` });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
function successHandler(response) {
|
||||
if(response.status == 200) {
|
||||
if(typeof response.data.message !== 'undefined') {
|
||||
toast.success(response.data.message, response.data.title);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
// apply interceptor on response
|
||||
axios.interceptors.response.use(successHandler, errorResponseHandler);
|
||||
|
||||
export default errorResponseHandler;
|
||||
@@ -0,0 +1,21 @@
|
||||
import "izitoast/dist/css/iziToast.min.css";
|
||||
import iZtoast from "izitoast";
|
||||
|
||||
const toast = {
|
||||
error: (message, title = "Error") => {
|
||||
return iZtoast.error({
|
||||
title: title,
|
||||
message: message,
|
||||
position: "bottomCenter"
|
||||
});
|
||||
},
|
||||
success: (message, title = "Success") => {
|
||||
return iZtoast.success({
|
||||
title: title,
|
||||
message: message,
|
||||
position: "bottomCenter"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default toast;
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './global/api.service';
|
||||
export * from './auth/storage.service';
|
||||
export * from './auth/user.service';
|
||||
@@ -0,0 +1,6 @@
|
||||
import {$hasRole} from '../acl/role';
|
||||
export default {
|
||||
methods: {
|
||||
$hasRole
|
||||
},
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user