Browse Source

双Token验证登录,权限管理基础搭建,持久化未处理

厅长信箱
21819 2 years ago
parent
commit
55d7c6b04d
  1. 1
      package.json
  2. 20
      src/components/HolidayList.vue
  3. 27
      src/components/LoginView.vue
  4. 9
      src/components/MailDetail.vue
  5. 103
      src/components/ManageMail.vue
  6. 90
      src/components/ManageUser.vue
  7. 21
      src/layout/Index.vue
  8. 4
      src/main.js
  9. 9
      src/router/index.js
  10. 23
      src/stores/useTokenStore.js
  11. 76
      src/util/axios_config.js

1
package.json

@ -13,6 +13,7 @@
"axios": "^1.6.5",
"element-plus": "^2.5.1",
"pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0",
"vue": "^3.3.11",
"vue-json-excel": "^0.3.0",
"vue-router": "^4.2.5"

20
src/components/HolidayList.vue

@ -35,7 +35,7 @@
<script setup>
import { ref, onMounted, onBeforeMount } from 'vue';
import { ElMessage } from 'element-plus'
import axios from 'axios';
import { request } from '../util/axios_config'
const currenYear = ref('');
const loading = ref(true);
@ -46,10 +46,12 @@ const dayType = ref({
});
const getDateData = () => {
axios.get('/api/outer/holiday/show-holiday').then(res => {
request({
url: '/api/outer/holiday/show-holiday',
method: 'GET'
}).then(res => {
dayType.value = res.data;
loading.value = false;
console.log(dayType.value);
}).catch(err => {
console.log(err);
});
@ -71,13 +73,11 @@ const initCalendar = (year) => {
for (let i = 0; i < 12; i++)
months.push({ cal: new Date(year, i, 1) });
defaultCals.value = months;
// console.log(defaultCals.value);
};
const searchHoliday = () => {
loading.value = true;
let nowYear = new Date().getFullYear();
console.log(currenYear.value + '==' + nowYear);
if (currenYear.value === String(nowYear)) {
getDateData();
setTimeout(() => {
@ -92,8 +92,12 @@ const searchHoliday = () => {
const refreshHoliday = () => {
loading.value = true;
axios.post('/api/outer/holiday/refresh-holiday', { year: currenYear.value }, { headers: { 'Content-Type': 'application/json' } }).then(res => {
// console.log(res.data);
request({
url: '/api/outer/holiday/refresh-holiday',
method: 'POST',
data: { year: currenYear.value },
headers: { 'Content-Type': 'application/json' }
}).then(res => {
dayType.value = res.data.holidayList;
setTimeout(() => {
loading.value = false;
@ -106,7 +110,6 @@ const refreshHoliday = () => {
};
const ifHoliday = (day) => {
// console.log('Comparing dayType.value.date:', dayType.value.date, 'with day:', day);
for (let i = 0; i < dayType.value.length; i++)
if (dayType.value[i].date === day && dayType.value[i].holidayFlag === 'Y')
return true;
@ -114,7 +117,6 @@ const ifHoliday = (day) => {
};
const ifAdjustDay = (day) => {
// console.log('Comparing dayType.value.date:', dayType.value.date, 'with day:', day);
for (let i = 0; i < dayType.value.length; i++)
if (dayType.value[i].date === day && dayType.value[i].holidayFlag === 'N')
return true;

27
src/components/LoginView.vue

@ -20,9 +20,12 @@
<script setup>
import { reactive } from 'vue'
import axios from 'axios'
import { request } from '../util/axios_config'
import router from '../router'
import { ElMessage } from 'element-plus'
import { useTokenStore } from '../stores/useTokenStore'
const tokens = useTokenStore()
const login = reactive({
account: '',
@ -35,9 +38,13 @@ const inputCheck = () => {
}
const sendCaptcha = () => {
axios.post('/api/captcha', login, { headers: { 'Content-Type': 'application/json' } }).then(res => {
request({
url: '/api/captcha',
method: 'POST',
data: login,
headers: { 'Content-Type': 'application/json' }
}).then(res => {
ElMessage.success('验证码发送成功')
console.log(res)
login.captcha = res.data
}).catch(err => {
ElMessage.error('验证码发送失败')
@ -46,10 +53,16 @@ const sendCaptcha = () => {
}
const loginIn = () => {
axios.post('/api/login', login, { headers: { 'Content-Type': 'application/json' } }).then(res => {
console.log(res)
if (res.data === 200) {
sessionStorage.setItem('user', login.account)
request({
url: '/api/login',
method: 'POST',
data: login,
headers: { 'Content-Type': 'application/json' }
}).then(res => {
if (res.data.stateCode === 200) {
tokens.setAccessToken(res.data.accessToken)
tokens.setRefreshToken(res.data.refreshToken)
console.log("localStorage.getItem('user'):" + localStorage.getItem('user'))
ElMessage.success('登录成功')
router.push('/')
}

9
src/components/MailDetail.vue

@ -46,7 +46,7 @@
<script setup>
import { ref, onMounted } from 'vue';
import router from '../router';
import axios from 'axios';
import { request } from '../util/axios_config'
const mailID = router.currentRoute.value.params.id;
const form = ref({
@ -60,9 +60,12 @@ const form = ref({
});
onMounted(() => {
axios.post('/api/mailbox/detail', { id: mailID }).then(res => {
request({
url: '/api/mailbox/detail',
method: 'POST',
data: { id: mailID }
}).then(res => {
form.value = res.data;
console.log(res.data);
if (res.data.satisfaction === "SATISFIED") {
form.value.satisfaction = "满意";
} else if (res.data.satisfaction === "NOT_SATISFIED") {

103
src/components/ManageMail.vue

@ -62,7 +62,7 @@
</el-row>
</el-form>
<div class="table-box" ref="tableBoxHeight">
<div class="table-box" ref="tableBoxHeight" v-loading="loading">
<el-table :data="tableData" border :height="tableHeight" table-layout="fixed"
:header-cell-style="{ 'background-color': '#EBEEFC', 'color': '#1D2C86' }">
<el-table-column fixed="left" prop="id" label="案件编号" width="200px">
@ -97,10 +97,10 @@
</template>
<script setup>
import { nextTick, ref } from 'vue'
import axios from 'axios'
import { onMounted, onUpdated } from 'vue';
import { request } from '../util/axios_config'
import { onMounted, ref } from 'vue';
import router from '../router';
const loading = ref(true);
const form = ref({
date: '',
@ -121,35 +121,49 @@ const pageData = ref({
totalSize: 0
})
onMounted(() => {
const requestData = {
formData: form.value,
pageData: pageData.value
const tableBoxHeight = ref(null)
const tableHeight = ref('100%')
const flexColumnWidth = (label, prop) => {
const width = Math.max(label.length * 12, 120)
return `${width}px`
}
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/mailbox/list-submit', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
console.log(response);
const handleResponse = (response) => {
tableData.value = response.data.mails;
tableData.value.forEach(item => {
item.createTime = item.createTime.split('T')[0]
})
pageData.value.totalSize = response.data.pageSet.totalSize;
})
loading.value = false;
}
const makeRequest = (requestData, callback) => {
const data = JSON.stringify(requestData)
request({
url: 'api/mailbox/list-submit',
method: 'POST',
data: data,
headers: { 'Content-Type': 'application/json' }
}).then(callback)
.catch(function (error) { console.log(error) })
}
const updateData = (requestData) => {
makeRequest(requestData, function (response) {
handleResponse(response)
})
const tableBoxHeight = ref(null)
const tableHeight = ref('100%')
const flexColumnWidth = (label, prop) => {
const width = Math.max(label.length * 12, 120)
return `${width}px`
}
onMounted(() => {
const requestData = {
formData: form.value,
pageData: pageData.value
}
updateData(requestData)
})
const handleDetail = (index) => {
console.log(index)
console.log(tableData.value[index - 1].id)
router.push('/mailbox/detail/' + tableData.value[index - 1].id)
}
@ -159,17 +173,7 @@ const handleSizeChange = (size) => {
pageData: pageData.value
}
pageData.value.pageSize = size
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/mailbox/list-submit', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
tableData.value = response.data.mails;
tableData.value.forEach(item => {
item.createTime = item.createTime.split('T')[0]
})
pageData.value.totalSize = response.data.pageSet.totalSize;
})
.catch(function (error) { console.log(error) })
updateData(requestData)
}
const handlePageChange = (currentPage) => {
@ -178,17 +182,7 @@ const handlePageChange = (currentPage) => {
pageData: pageData.value
}
pageData.value.currentPage = currentPage
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/mailbox/list-submit', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
tableData.value = response.data.mails;
tableData.value.forEach(item => {
item.createTime = item.createTime.split('T')[0]
})
pageData.value.totalSize = response.data.pageSet.totalSize;
})
.catch(function (error) { console.log(error) })
updateData(requestData)
}
const search = () => {
@ -196,17 +190,7 @@ const search = () => {
formData: form.value,
pageData: pageData.value
}
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/mailbox/list-submit', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
tableData.value = response.data.mails;
tableData.value.forEach(item => {
item.createTime = item.createTime.split('T')[0]
})
pageData.value.totalSize = response.data.pageSet.totalSize;
})
.catch(function (error) { console.log(error) })
updateData(requestData)
}
const reset = () => {
@ -227,8 +211,13 @@ const out = () => {
pageData: pageData.value
}
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/mailbox/exportexcel', data, { headers: { 'Content-Type': 'application/json' }, responseType: 'blob' }).then(function (res) {
request({
url: 'api/mailbox/exportexcel',
method: 'POST',
data: data,
headers: { 'Content-Type': 'application/json' },
responseType: 'blob'
}).then(function (res) {
var blob = new Blob([res.data], { type: 'application/octet-stream;charset=UTF-8' })
var contentDisposition = res.headers['content-disposition']
var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')

90
src/components/ManageUser.vue

@ -65,7 +65,7 @@
</el-row>
</el-form>
<div class="table-box" ref="tableBoxHeight">
<div class="table-box" ref="tableBoxHeight" v-loading="loading">
<el-table :data="tableData" border :height="tableHeight" table-layout="fixed"
:header-cell-style="{ 'background-color': '#EBEEFC', 'color': '#1D2C86' }">
<el-table-column prop="createTime" label="用户创建日期" width="120px">
@ -98,10 +98,11 @@
</template>
<script setup>
import axios from 'axios'
import { request } from '../util/axios_config'
import { onMounted, ref } from 'vue';
import { ElMessage } from 'element-plus'
const loading = ref(true);
const form = ref({
date: '',
realName: '',
@ -124,24 +125,31 @@ const pageData = ref({
totalSize: 0
})
onMounted(() => {
const requestData = {
formData: form.value,
pageData: pageData.value
}
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/user/list-submit', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
// console.log(response);
const getData = (data) => {
request({
url: 'api/user/list-submit',
method: 'POST',
data: data,
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
tableData.value = response.data.users;
tableData.value.forEach(item => {
item.createTime = item.createTime.split('T')[0]
})
pageData.value.totalSize = response.data.pageSet.totalSize;
loading.value = false;
})
.catch(function (error) { console.log(error) })
}
onMounted(() => {
const requestData = {
formData: form.value,
pageData: pageData.value
}
const data = JSON.stringify(requestData)
getData(data)
})
const tableBoxHeight = ref(null)
const tableHeight = ref('100%')
@ -151,11 +159,11 @@ const flexColumnWidth = (label, prop) => {
}
const handleDelete = (index) => {
console.log(index)
console.log(tableData.value[index - 1].id)
axios.post('api/user/delete-user', { id: tableData.value[index - 1].id })
.then(function (response) {
// console.log(response);
request({
url: 'api/user/delete-user',
method: 'POST',
data: { id: tableData.value[index - 1].id },
}).then(function (response) {
if (response.status === 200 && response.data === 'success') {
search()
successMessage('删除用户成功')
@ -174,17 +182,7 @@ const handleSizeChange = (size) => {
}
pageData.value.pageSize = size
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/user/list-submit', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
// console.log(response);
tableData.value = response.data.users;
tableData.value.forEach(item => {
item.createTime = item.createTime.split('T')[0]
})
pageData.value.totalSize = response.data.pageSet.totalSize;
})
.catch(function (error) { console.log(error) })
getData(data)
}
const handlePageChange = (currentPage) => {
@ -194,17 +192,7 @@ const handlePageChange = (currentPage) => {
}
pageData.value.currentPage = currentPage
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/user/list-submit', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
// console.log(response);
tableData.value = response.data.users;
tableData.value.forEach(item => {
item.createTime = item.createTime.split('T')[0]
})
pageData.value.totalSize = response.data.pageSet.totalSize;
})
.catch(function (error) { console.log(error) })
getData(data)
}
const search = () => {
@ -213,17 +201,7 @@ const search = () => {
pageData: pageData.value
}
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/user/list-submit', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
// console.log(response);
tableData.value = response.data.users;
tableData.value.forEach(item => {
item.createTime = item.createTime.split('T')[0]
})
pageData.value.totalSize = response.data.pageSet.totalSize;
})
.catch(function (error) { console.log(error) })
getData(data)
}
const reset = () => {
@ -242,10 +220,12 @@ const newUser = ref(false)
const submitNewUser = () => {
const requestData = newForm.value
const data = JSON.stringify(requestData)
console.log(data)
axios.post('api/user/add-user', data, { headers: { 'Content-Type': 'application/json' } })
.then(function (response) {
console.log(response);
request({
url: 'api/user/add-user',
method: 'POST',
data: data,
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
if (response.status === 200 && response.data === 'success') {
newUser.value = false;
newFormReset();

21
src/layout/Index.vue

@ -41,20 +41,27 @@
<main style="width: 100%;"><router-view /></main>
</div>
</template>
<script setup>
import { HomeFilled, Platform, Setting, Menu, User } from '@element-plus/icons-vue'
<script setup>
import { HomeFilled, Platform, Menu, User } from '@element-plus/icons-vue'
import { useRouter } from "vue-router";
import axios from 'axios';
import { useTokenStore } from '../stores/useTokenStore';
import { request } from '../util/axios_config';
import { ElMessage } from 'element-plus'
const router = useRouter();
const logout = () => {
sessionStorage.removeItem('user');
axios.post('/api/logout')
.then((res) => { if (res.data === 200) { ElMessage.success('登出成功'); } })
request({
url: 'api/logout',
method: 'POST'
}).then((res) => {
if (res.data === 200) {
const tokens = useTokenStore();
tokens.removeTokens();
ElMessage.success('登出成功');
}
})
.catch((e) => { console.log(e) });
router.push('/login');
}

4
src/main.js

@ -5,14 +5,14 @@ import App from './App.vue'
import IconComponent from '@/components/Icon.vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import piniaPersist from 'pinia-plugin-persist'
import './assets/style/style.scss'
import 'element-plus/theme-chalk/src/message.scss'
createApp(App)
.use(router)
.use(ElementPlus, { locale: zhCn })
.use(createPinia())
.use(createPinia().use(piniaPersist))
.component('Icon', IconComponent)
.mount('#app')

9
src/router/index.js

@ -1,4 +1,6 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import { getActivePinia } from 'pinia';
import { useTokenStore } from "@/stores/useTokenStore";
import Home from '@/views/Home.vue'
import Layout from '@/layout/Index.vue'
@ -53,8 +55,11 @@ const router = createRouter({
});
router.beforeEach((to, from, next) => {
const user = sessionStorage.getItem("user");
if (!user && to.path !== '/login') {
const data = sessionStorage.getItem('token');
console.log(data);
const tokens = useTokenStore(getActivePinia());
const refreshToken = tokens.refresh_token;
if (!refreshToken && to.path !== '/login') {
next('/login');
} else {
next();

23
src/stores/useTokenStore.js

@ -0,0 +1,23 @@
import { defineStore } from 'pinia'
export const useTokenStore = defineStore('token', {
state: () => ({
access_token: null,
refresh_token: null,
}),
actions: {
setAccessToken(token) {
this.access_token = token
},
setRefreshToken(token) {
this.refresh_token = token
},
removeTokens() {
this.access_token = null
this.refresh_token = null
}
},
persist: {
enabled: true,
}
})

76
src/util/axios_config.js

@ -0,0 +1,76 @@
import axios from 'axios'
import { getActivePinia } from 'pinia'
import { useTokenStore } from "@/stores/useTokenStore";
import router from "@/router";
axios.defaults.baseURL = ''
axios.defaults.timeout = 10000
// 注册请求拦截器
axios.interceptors.request.use(config => {
const pinia = getActivePinia()
const tokens = useTokenStore(pinia)
const accessToken = tokens.access_token
if (accessToken) {
config.headers['Authorization'] = 'Bearer ' + accessToken
// console.log(config.headers)
}
// console.log(config.headers)
return config
}, error => {
console.log(error)
return Promise.reject(error)
})
// 注册响应拦截器
axios.interceptors.response.use(response => {
const pinia = getActivePinia()
const tokens = useTokenStore(pinia)
const newAccessToken = response.data.accessToken
if (newAccessToken) {
tokens.access_token = newAccessToken
}
// console.log("res.interceptors-:" + JSON.stringify(response))
return response
}, async (error) => {
const pinia = getActivePinia()
const tokens = useTokenStore(pinia)
// console.log("err.interceptors-:" + JSON.stringify(error.response))
// 401 错误,说明 access_token 过期了,需要用 refresh_token 来刷新
if (error.response && error.response.status === 401) {
const refreshToken = tokens.refresh_token
if (refreshToken) {
try {
// console.log("refresh-token-req:" + refreshToken)
const res = await axios.create().post('api/refresh-token', { refreshToken: refreshToken })
// console.log("refresh-token-res:" + JSON.stringify(res))
// 如果刷新成功,就更新本地存储中的 token,并且重新发送之前失败的请求
if (res.data && res.data.accessToken) {
tokens.setAccessToken(res.data.accessToken)
tokens.setRefreshToken(res.data.refreshToken)
return axios.request(error.config)
}
} catch (err) {
// 如果刷新失败,就清除本地存储中的 token,并且跳转到登录页面
tokens.removeTokens()
// 给用户一个提示或者一个重试的机会
alert('您的登录已过期,请重新登录')
// 将用户的当前状态保存起来,以便在登录后恢复
localStorage.setItem('current_route', router.currentRoute.value)
router.push('/login')
}
}
}
error.message = '请求失败:' + error.message
if (error.response && error.response.status === 404) {
error = new NotFoundError(error.message)
}
return Promise.reject(error)
})
export function request(config) {
return axios(config)
}
Loading…
Cancel
Save