app2登录认证与权限控制实现 #71

Merged
hnu202326010125 merged 4 commits from luoyuehang_branch into develop 1 month ago

@ -1,15 +1,17 @@
// src/main.js
import './assets/main.css'
import './assets/mobile.css' // 添加这行
import './assets/mobile.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import './router/permission' // 确保引入了路由守卫
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
app.mount('#app')

@ -0,0 +1,30 @@
// src/router/permission.js
import router from './index'
// 不需要登录的白名单路由
const whiteList = ['/', '/login', '/register']
router.beforeEach((to, from, next) => {
// 检查是否有有效的token
const token = localStorage.getItem('token')
if (token) {
// 有token的情况下
if (to.path === '/' || to.path === '/login') {
// 已登录用户访问登录页时重定向到首页
next('/home')
} else {
// 访问其他需要权限的页面,允许通过
next()
}
} else {
// 没有token的情况下
if (whiteList.includes(to.path)) {
// 白名单路由可以直接访问
next()
} else {
// 非白名单路由重定向到登录页
next('/')
}
}
})

@ -2,10 +2,44 @@
import axios from 'axios'
const apiClient = axios.create({
baseURL: 'http://localhost:8080', // Adjust to your backend URL
baseURL: 'http://localhost:8080',
headers: {
'Content-Type': 'application/json'
}
})
// 请求拦截器
apiClient.interceptors.request.use(
(config) => {
// 从本地存储获取token
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => {
return Promise.reject(error)
}
)
// 响应拦截器
apiClient.interceptors.response.use(
(response) => {
return response
},
(error) => {
if (error.response?.status === 401) {
// token过期或无效清除用户信息并跳转到登录页
localStorage.removeItem('token')
localStorage.removeItem('userId')
localStorage.removeItem('username')
localStorage.removeItem('userType')
localStorage.removeItem('studentId')
window.location.href = '/'
}
return Promise.reject(error)
}
)
export default apiClient

@ -0,0 +1,32 @@
// src/services/deviceService.js
import api from './api'
export const deviceService = {
// 获取终端设备信息
async getTerminalInfo(terminalId) {
try {
const response = await api.get(`/api/water/terminal/${terminalId}`)
return response.data
} catch (error) {
// 更好的错误处理
if (error.response?.status === 403) {
console.error('权限不足,请重新登录')
// 可以在这里触发重新登录逻辑
}
throw error.response?.data || error.message
}
},
// 获取水质信息
async getWaterQualityInfo(deviceId) {
try {
const response = await api.get(`/api/water/quality/${deviceId}`)
return response.data
} catch (error) {
if (error.response?.status === 403) {
console.error('权限不足,无法获取水质信息')
}
throw error.response?.data || error.message
}
}
}

@ -0,0 +1,30 @@
// src/stores/auth.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue' // 添加 computed 导入
export const useAuthStore = defineStore('auth', () => {
const user = ref(null)
const token = ref(localStorage.getItem('token'))
const login = (userData, authToken) => {
user.value = userData
token.value = authToken
localStorage.setItem('token', authToken)
}
const logout = () => {
user.value = null
token.value = null
localStorage.removeItem('token')
}
const isAuthenticated = computed(() => !!token.value) // 使用 computed 包装
return {
user,
token,
isAuthenticated,
login,
logout
}
})

@ -0,0 +1,67 @@
// src/stores/user.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserStore = defineStore('user', () => {
const token = ref(localStorage.getItem('token') || '')
const userId = ref(localStorage.getItem('userId') || '')
const username = ref(localStorage.getItem('username') || '')
const userType = ref(localStorage.getItem('userType') || '')
const studentId = ref(localStorage.getItem('studentId') || '')
// 计算属性:是否已登录
const isLoggedIn = computed(() => !!token.value)
// 设置用户信息
const setUser = (userInfo) => {
token.value = userInfo.token
userId.value = userInfo.userId
username.value = userInfo.username
userType.value = userInfo.userType
studentId.value = userInfo.studentId
// 保存到本地存储
localStorage.setItem('token', userInfo.token)
localStorage.setItem('userId', userInfo.userId)
localStorage.setItem('username', userInfo.username)
localStorage.setItem('userType', userInfo.userType)
localStorage.setItem('studentId', userInfo.studentId)
}
// 清除用户信息
const clearUser = () => {
token.value = ''
userId.value = ''
username.value = ''
userType.value = ''
studentId.value = ''
// 清除本地存储
localStorage.removeItem('token')
localStorage.removeItem('userId')
localStorage.removeItem('username')
localStorage.removeItem('userType')
localStorage.removeItem('studentId')
}
// 从本地存储初始化用户信息
const initFromStorage = () => {
token.value = localStorage.getItem('token') || ''
userId.value = localStorage.getItem('userId') || ''
username.value = localStorage.getItem('username') || ''
userType.value = localStorage.getItem('userType') || ''
studentId.value = localStorage.getItem('studentId') || ''
}
return {
token,
userId,
username,
userType,
studentId,
isLoggedIn,
setUser,
clearUser,
initFromStorage
}
})

@ -152,20 +152,24 @@
</template>
<script setup>
// ProfilePage.vue script setup
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
const router = useRouter()
const userStore = useUserStore()
//
const userInfo = reactive({
lastName: '',
fullName: '张三',
studentId: '20212601212',
lastName: '',
fullName: '',
studentId: '',
college: '信息科学与工程学院',
class: '软件2301班'
})
//
const userStats = reactive({
days: '26天',
@ -220,15 +224,15 @@ const goToSettings = () => {
// 退
const handleLogout = () => {
if (confirm('确定要退出登录吗?')) {
//
localStorage.removeItem('studentId')
localStorage.removeItem('studentName')
//
userStore.clearUser()
//
router.push('/')
}
}
//
const goToPage = (page) => {
switch(page) {
@ -245,17 +249,11 @@ const goToPage = (page) => {
}
onMounted(() => {
// API
const savedStudentId = localStorage.getItem('studentId')
const savedStudentName = localStorage.getItem('studentName')
if (savedStudentId) {
userInfo.studentId = savedStudentId
}
if (savedStudentName) {
userInfo.fullName = savedStudentName
userInfo.lastName = savedStudentName.charAt(0)
//
if (userStore.isLoggedIn) {
userInfo.studentId = userStore.studentId
userInfo.fullName = userStore.username
userInfo.lastName = userStore.username.charAt(0)
}
//

@ -222,6 +222,20 @@
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { authServices } from '@/services/authServices' //
import { onMounted } from 'vue'
onMounted(() => {
//
const token = localStorage.getItem('token')
if (token) {
// token
router.push('/home')
}
//
initRememberedUser()
})
const router = useRouter()
@ -317,6 +331,7 @@ const validateRegister = () => {
}
//
// StudentLoginPage.vue handleLogin
const handleLogin = async () => {
if (!validateLogin()) return
@ -378,6 +393,7 @@ const handleLogin = async () => {
}
//
// <script setup> handleRegister
const handleRegister = async () => {

Loading…
Cancel
Save