1.网站开发中为什么必要权限控制
掩护敏感信息:确保只有授权用户才华访问特定命据。
增强安全性:防御未经授权的访问和其他安全威胁。
满意合规要求:服从相干法律法规,如处理处罚个人或财务信息的规定。
提拔用户体验:为差别脚色定制化访问和服务,简化界面。
支持多脚色操纵:答应基于用户脚色分配差别的访问级别和功能。
防止误操纵:限定关键操纵仅限于指定职员实行,镌汰错误风险。
审计追踪:记任命户活动以便查察和题目排查。
维护数据同等性:防止未经授权的数据修改,保持数据正确性和完备性。
2.下载Pinia
npm install pina
3.设置Pinia
- import { createPinia } from 'pinia'
复制代码- const pinia = createPinia()
- app.use(pinia)
复制代码 4.新建store文件夹,创建user文件设置权限列表
- // src/stores/user.js
- import {defineStore} from 'pinia'
- export const useUserStore = defineStore('user', {
- state: () => ({
- role: 'guest', // 默认角色为访客
- menus: [
- {name: '主页', path: '/', permission: ['guest', 'user', 'admin']},
- {name: '用户面板', path: '/dashboard', permission: ['user', 'admin']},
- {name: '管理员面板', path: '/admin', permission: ['admin']},
- {name: ' 产品管理', path: '/product', permission: ['admin']}
- ]
- }),
- getters: {
- accessibleMenus: (state) => {
- return state.menus.filter(menu => menu.permission.includes(state.role));
- }
- },
- actions: {
- setRole(role) {
- this.role = role;
- }
- }
- })
复制代码 5.创建router.js文件设置路由
- // src/router/index.js
- import {createRouter, createWebHistory} from 'vue-router'
- import Home from '../views/Home.vue'
- import Dashboard from '../views/Dashboard.vue'
- import AdminPanel from '../views/AdminPanel.vue'
- import Product from '../views/ProductManager.vue'
- import {useUserStore} from '../store/user'
- const routes = [
- {path: '/', component: Home},
- {path: '/dashboard', component: Dashboard, meta: {requiresAuth: true, roles: ['user', 'admin']}},
- {path: '/admin', component: AdminPanel, meta: {requiresAuth: true, roles: ['admin']}},
- {path: '/product', component: Product, meta: {requiresAuth: true, roles: ['admin']}}
- ]
- const router = createRouter({
- history: createWebHistory(),
- routes
- })
- router.beforeEach(async (to, from, next) => {
- const userStore = useUserStore()
- if (to.matched.some(record => record.meta.requiresAuth)) {
- if (!to.meta.roles.includes(userStore.role)) {
- next({path: '/'})
- } else {
- next()
- }
- } else {
- next()
- }
- })
- export default router
复制代码 6.创建vue所需组件
- <script setup>
- import { onMounted, ref } from 'vue'
- import axios from "axios";
- // 定义产品列表
- const products = ref([])
- // 获取所有产品
- const getProducts = async () => {
- try {
- const response = await axios.get('http://localhost:8080/api/product/getAll');
- products.value = response.data;
- } catch (error) {
- console.error('获取产品列表时出错:', error);
- }
- };
- onMounted(() => {
- getProducts();
- })
- </script>
- <template>
- <div class="product-page">
- <!-- 展示产品列表 -->
- <section class="product-list-section">
- <h2>我们的产品</h2>
- <ul class="product-list">
- <li v-for="product in products" :key="product.id" class="product-item">
- <img :src="product.image" alt="产品图片" class="product-image">
- <div class="product-info">
- <h3>{{ product.content }}</h3>
- <p>{{ product.addTime }}</p>
- </div>
- </li>
- </ul>
- </section>
- </div>
- </template>
- <style scoped>
- .product-page {
- font-family: 'Microsoft YaHei', Arial, sans-serif;
- text-align: center;
- background-color: #f4f4f4;
- }
- .product-list-section {
- padding: 50px 20px;
- }
- .product-list {
- list-style-type: none;
- padding: 0;
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- }
- .product-item {
- background-color: white;
- margin: 10px;
- border-radius: 10px;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- width: 300px;
- overflow: hidden;
- transition: transform 0.3s ease-in-out;
- }
- .product-item:hover {
- transform: scale(1.05);
- }
- .product-image {
- width: 100%;
- height: auto;
- border-top-left-radius: 10px;
- border-top-right-radius: 10px;
- }
- .product-info {
- padding: 15px;
- }
- .product-info h3 {
- margin-top: 0;
- font-size: 1.2em;
- color: #333;
- }
- .product-info p {
- font-size: 1em;
- color: #666;
- }
- </style>
复制代码- <script setup>
- import {onMounted, ref} from 'vue'
- import {useUserStore} from '../store/user'
- const userStore = useUserStore()
- // 示例数据
- const users = ref([])
- // 模拟获取用户列表的方法
- const fetchUsers = () => {
- // 这里可以替换为实际的API调用
- setTimeout(() => {
- users.value = [
- {id: 1, name: '张伟', role: 'admin'},
- {id: 2, name: '李娜', role: 'user'}
- ]
- }, 1000)
- }
- onMounted(() => {
- if (userStore.role === 'admin') {
- fetchUsers()
- }
- })
- </script>
- <template>
- <div class="admin-panel">
- <header class="panel-header">
- <h1>管理员面板</h1>
- <p>欢迎,管理员!</p>
- </header>
- <!-- 用户列表 -->
- <section v-if="users.length > 0" class="user-list-section">
- <h2>用户列表</h2>
- <ul>
- <li v-for="user in users" :key="user.id" class="user-item">
- <span>{{ user.name }}</span> -
- <span>{{ user.role === 'admin' ? '管理员' : '普通用户' }}</span>
- </li>
- </ul>
- </section>
- <section v-else class="loading-section">
- <p>加载用户中...</p>
- </section>
- </div>
- </template>
- <style scoped>
- .admin-panel {
- max-width: 800px;
- margin: 0 auto;
- padding: 20px;
- background-color: #f9f9f9;
- border-radius: 8px;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- font-family: 'Microsoft YaHei', Arial, sans-serif;
- }
- .panel-header {
- text-align: center;
- margin-bottom: 20px;
- }
- .panel-header h1 {
- color: #333;
- font-size: 2em;
- }
- .panel-header p {
- color: #666;
- font-size: 1.2em;
- }
- .user-list-section, .loading-section {
- text-align: center;
- }
- .user-list-section ul {
- list-style-type: none;
- padding: 0;
- }
- .user-item {
- background-color: #fff;
- margin-bottom: 10px;
- padding: 15px;
- border-radius: 4px;
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .user-item span:first-child {
- font-weight: bold;
- }
- .loading-section p {
- font-size: 1.2em;
- color: #666;
- }
- </style>
复制代码- <template>
- <div class="product-management">
- <!-- 添加产品的弹窗 -->
- <div v-if="isAddModalVisible" class="modal-overlay" @click.self="closeAddModal">
- <div class="modal-content">
- <span class="close" @click="closeAddModal">×</span>
- <h2>添加产品</h2>
- <form @submit.prevent="saveProduct()">
- <div class="form-group">
- <label for="content">内容:</label>
- <input type="text" id="content" v-model="addProduct.content" required />
- </div>
- <div class="form-group">
- <label for="image">图片URL:</label>
- <input type="url" id="image" v-model="addProduct.image" required />
- </div>
- <button type="submit">保存</button>
- </form>
- </div>
- </div>
- <!-- 编辑产品的弹窗 -->
- <div v-if="isEditModalVisible" class="modal-overlay" @click.self="closeEditModal">
- <div class="modal-content">
- <span class="close" @click="closeEditModal">×</span>
- <h2>编辑产品</h2>
- <form @submit.prevent="updateProduct()">
- <div class="form-group">
- <label for="editContent">内容:</label>
- <input type="text" id="editContent" v-model="editProductData.content" required />
- </div>
- <div class="form-group">
- <label for="editImage">图片URL:</label>
- <input type="url" id="editImage" v-model="editProductData.image" required />
- </div>
- <button type="submit">更新</button>
- </form>
- </div>
- </div>
- <!-- 产品列表 -->
- <div class="product-list">
- <h2>产品列表</h2>
- <ul>
- <li v-for="(item, index) in products" :key="index" class="product-item">
- <img :src="item.image" alt="Product Image" class="product-image" @click="showImage(item.image)">
- <div class="product-info">
- <span>{{ item.content }}</span>
- <span>{{ item.addTime }}</span>
- </div>
- <div class="actions">
- <button @click="editProduct(item)">编辑</button>
- <button @click="deleteProduct(item)">删除</button>
- </div>
- </li>
- </ul>
- </div>
- <!-- 添加产品的按钮 -->
- <button class="add-product-button" @click="openAddModal">添加产品</button>
- <!-- Lightbox 图片预览 -->
- <vue-easy-lightbox
- :visible="visible"
- :imgs="imgs"
- @hide="handleHide"
- ></vue-easy-lightbox>
- </div>
- </template>
- <script>
- import { ref, onMounted } from 'vue';
- import axios from 'axios';
- import VueEasyLightbox from 'vue-easy-lightbox';
- export default {
- components: { VueEasyLightbox },
- setup() {
- const isAddModalVisible = ref(false);
- const isEditModalVisible = ref(false);
- const addProduct = ref({ content: '', image: '' });
- const editProductData = ref({ content: '', image: '' });
- const products = ref([]);
- const currentProductId = ref(null);
- const visible = ref(false);
- const imgs = ref('');
- // 打开添加产品的模态框
- const openAddModal = () => {
- isAddModalVisible.value = true;
- };
- // 关闭添加产品的模态框
- const closeAddModal = () => {
- isAddModalVisible.value = false;
- resetAddForm();
- };
- // 清空添加表单
- const resetAddForm = () => {
- addProduct.value.content = '';
- addProduct.value.image = '';
- };
- // 打开编辑产品的模态框
- const openEditModal = () => {
- isEditModalVisible.value = true;
- };
- // 关闭编辑产品的模态框
- const closeEditModal = () => {
- isEditModalVisible.value = false;
- resetEditForm();
- };
- // 清空编辑表单
- const resetEditForm = () => {
- editProductData.value.content = '';
- editProductData.value.image = '';
- };
- // 保存产品
- const saveProduct = async () => {
- try {
- await axios.post('http://localhost:8080/api/product/save', addProduct.value);
- await getProducts();
- closeAddModal();
- } catch (error) {
- console.error('保存产品时出错:', error);
- }
- };
- // 更新产品
- const updateProduct = async () => {
- try {
- await axios.put(`http://localhost:8080/api/product/update/${currentProductId.value}`, editProductData.value);
- await getProducts();
- closeEditModal();
- } catch (error) {
- console.error('更新产品时出错:', error);
- }
- };
- // 删除产品
- const deleteProduct = async (item) => {
- if (confirm('确定要删除此产品吗?')) {
- try {
- await axios.delete(`http://localhost:8080/api/product/delete/${item.id}`);
- await getProducts();
- } catch (error) {
- console.error('删除产品时出错:', error);
- }
- }
- };
- // 编辑产品
- const editProduct = (item) => {
- currentProductId.value = item.id;
- editProductData.value = { ...item };
- openEditModal();
- };
- // 获取所有产品
- const getProducts = async () => {
- try {
- const response = await axios.get('http://localhost:8080/api/product/getAll');
- products.value = response.data;
- } catch (error) {
- console.error('获取产品列表时出错:', error);
- }
- };
- // 显示大图
- const showImage = (src) => {
- imgs.value = src;
- visible.value = true;
- };
- // 隐藏大图
- const handleHide = () => {
- visible.value = false;
- };
- onMounted(() => {
- getProducts();
- });
- return {
- isAddModalVisible,
- isEditModalVisible,
- addProduct,
- editProductData,
- products,
- openAddModal,
- closeAddModal,
- openEditModal,
- closeEditModal,
- saveProduct,
- updateProduct,
- deleteProduct,
- editProduct,
- visible,
- imgs,
- showImage,
- handleHide
- };
- }
- };
- </script>
- <style scoped>
- .product-management {
- display: flex;
- flex-direction: column;
- align-items: center;
- font-family: 'Microsoft YaHei', Arial, sans-serif;
- }
- .add-product-button {
- margin-top: 20px;
- padding: 10px 20px;
- background-color: #4CAF50;
- color: white;
- border: none;
- cursor: pointer;
- font-size: 16px;
- border-radius: 5px;
- transition: background-color 0.3s ease;
- }
- .add-product-button:hover {
- background-color: #45a049;
- }
- .modal-overlay {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .modal-content {
- background-color: white;
- padding: 20px;
- border-radius: 8px;
- width: 400px;
- position: relative;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- }
- .close {
- position: absolute;
- top: 10px;
- right: 10px;
- font-size: 20px;
- cursor: pointer;
- }
- .form-group {
- margin-bottom: 15px;
- }
- .form-group label {
- display: block;
- margin-bottom: 5px;
- font-weight: bold;
- }
- .form-group input {
- width: 100%;
- padding: 8px;
- box-sizing: border-box;
- border: 1px solid #ccc;
- border-radius: 4px;
- }
- button[type="submit"] {
- background-color: #4CAF50;
- color: white;
- padding: 10px 15px;
- border: none;
- border-radius: 5px;
- cursor: pointer;
- font-size: 14px;
- transition: background-color 0.3s ease;
- }
- button[type="submit"]:hover {
- background-color: #45a049;
- }
- .product-list {
- max-width: 1000px;
- width: 100%;
- margin-top: 20px;
- }
- .product-list h2 {
- text-align: center;
- color: #333;
- font-size: 1.8em;
- margin-bottom: 20px;
- }
- .product-list ul {
- list-style-type: none;
- padding: 0;
- }
- .product-item {
- display: flex;
- align-items: center;
- margin-bottom: 15px;
- padding: 15px;
- border: 1px solid #ddd;
- border-radius: 8px;
- justify-content: space-between;
- background-color: #f9f9f9;
- transition: background-color 0.3s ease;
- }
- .product-item:hover {
- background-color: #e9e9e9;
- }
- .product-image {
- max-width: 120px;
- max-height: 120px;
- object-fit: cover;
- margin-right: 15px;
- cursor: pointer;
- }
- .product-info {
- flex-grow: 1;
- }
- .actions button {
- margin-left: 10px;
- padding: 5px 10px;
- background-color: #007bff;
- color: white;
- border: none;
- cursor: pointer;
- font-size: 14px;
- border-radius: 3px;
- transition: background-color 0.3s ease;
- }
- .actions button:hover {
- background-color: #0056b3;
- }
- </style>
复制代码 7.在App.vue中遍历Pinia数据获取权限列表
- <!-- src/App.vue -->
- <template>
- <div id="app">
- <!-- 导航栏 -->
- <nav class="menu-bar">
- <ul>
- <li v-for="menu in accessibleMenus" :key="menu.path" class="menu-item">
- <router-link :to="menu.path">{{ menu.name }}</router-link>
- </li>
- </ul>
- </nav>
- <!-- 路由视图 -->
- <router-view></router-view>
- </div>
- </template>
- <script setup>
- import { computed } from 'vue'
- import { useUserStore } from './store/user'
- // 使用用户状态管理
- const userStore = useUserStore()
- // 计算属性获取可访问菜单列表
- const accessibleMenus = computed(() => userStore.accessibleMenus)
- </script>
- <style scoped>
- /* 应用全局样式 */
- #app {
- font-family: 'Microsoft YaHei', Arial, sans-serif;
- }
- .menu-bar {
- background-color: #333;
- padding: 10px 0;
- }
- .menu-bar ul {
- list-style-type: none;
- margin: 0;
- padding: 0;
- display: flex;
- justify-content: center;
- }
- .menu-item {
- margin: 0 15px;
- }
- .menu-item a {
- color: white;
- text-decoration: none;
- padding: 8px 15px;
- border-radius: 5px;
- transition: background-color 0.3s ease-in-out;
- }
- .menu-item a:hover {
- background-color: #4CAF50;
- }
- .menu-item a.router-link-active {
- background-color: #4CAF50;
- font-weight: bold;
- }
- </style>
复制代码 8.在main.js里设置当前用户权限(user or admin)
- // src/main.jsimport { createApp } from 'vue'import App from './App.vue'import router from './router/router.js'import { createPinia } from 'pinia'
- import { useUserStore } from './store/user.js'import ElementPlus from 'element-plus'import 'element-plus/dist/index.css'const app = createApp(App)const pinia = createPinia()
- app.use(pinia)
- app.use(router)app.use(ElementPlus)const userStore = useUserStore()// 模仿登录逻辑userStore.setRole('admin') // 可以根据现实情况设置差别的脚色app.mount('#app')
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|