首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Vue 框架实现用户单点登录功能的详细方法

Vue 框架实现用户单点登录功能的详细方法

作者头像
小焱写作
发布2025-09-03 17:38:16
发布2025-09-03 17:38:16
3650
举报

代码教程

Vue实现用户单点登录功能技术方案

一、单点登录(SSO)概述

(一)什么是单点登录

单点登录(Single Sign-On, SSO)是一种身份验证机制,允许用户使用一组凭证(如用户名和密码)登录到多个相关系统,而无需为每个系统单独进行身份验证。

(二)SSO的优势
  • 用户体验:用户只需登录一次,即可访问多个系统
  • 安全性:集中管理用户凭证,减少密码泄露风险
  • 管理效率:简化用户管理,降低维护成本

二、Vue实现SSO的技术方案

(一)基于JWT的SSO方案
(二)核心技术栈
  • 前端:Vue 3 + Vue Router + Pinia
  • 认证服务器:基于OAuth2.0或OpenID Connect
  • Token管理:JWT (JSON Web Token)
  • 存储:localStorage或cookie

三、实现步骤

(一)创建认证状态管理
代码语言:javascript
复制
// stores/auth.ts
import { defineStore } from 'pinia';
import axios from 'axios';

export const useAuthStore = defineStore('auth', {
  state: () => ({
    token: localStorage.getItem('token') || null,
    user: JSON.parse(localStorage.getItem('user') || 'null'),
  }),
  getters: {
    isAuthenticated: (state) => !!state.token,
  },
  actions: {
    async login(username: string, password: string) {
      try {
        const response = await axios.post('/api/auth/login', {
          username,
          password,
        });
        
        const { token, user } = response.data;
        
        // 存储Token和用户信息
        this.token = token;
        this.user = user;
        
        // 保存到localStorage
        localStorage.setItem('token', token);
        localStorage.setItem('user', JSON.stringify(user));
        
        // 设置axios请求头
        axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
        
        return true;
      } catch (error) {
        this.logout();
        throw error;
      }
    },
    
    logout() {
      this.token = null;
      this.user = null;
      localStorage.removeItem('token');
      localStorage.removeItem('user');
      delete axios.defaults.headers.common['Authorization'];
    },
    
    async validateToken() {
      try {
        const response = await axios.get('/api/auth/validate');
        return response.data;
      } catch (error) {
        this.logout();
        return false;
      }
    },
  },
});
(二)路由守卫配置
代码语言:javascript
复制
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue';
import DashboardView from '../views/DashboardView.vue';
import LoginView from '../views/LoginView.vue';
import { useAuthStore } from '../stores/auth';

const routes = [
  {
    path: '/',
    name: 'Home',
    component: HomeView,
  },
  {
    path: '/dashboard',
    name: 'Dashboard',
    component: DashboardView,
    meta: {
      requiresAuth: true,
    },
  },
  {
    path: '/login',
    name: 'Login',
    component: LoginView,
  },
];

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes,
});

// 全局前置守卫
router.beforeEach(async (to, from, next) => {
  const authStore = useAuthStore();
  
  // 检查路由是否需要认证
  if (to.meta.requiresAuth) {
    // 检查用户是否已登录
    if (!authStore.isAuthenticated) {
      // 未登录则重定向到登录页
      next({ name: 'Login' });
    } else {
      // 已登录则验证Token有效性
      const isValid = await authStore.validateToken();
      if (!isValid) {
        next({ name: 'Login' });
      } else {
        next();
      }
    }
  } else {
    // 不需要认证的路由直接通过
    next();
  }
});

export default router;
(三)API请求拦截器
代码语言:javascript
复制
// utils/axios.ts
import axios from 'axios';
import { useAuthStore } from '../stores/auth';

const service = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 5000,
});

// 请求拦截器
service.interceptors.request.use(
  (config) => {
    const authStore = useAuthStore();
    if (authStore.token) {
      config.headers.Authorization = `Bearer ${authStore.token}`;
    }
    return config;
  },
  (error) => {
    console.error('Request error:', error);
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  (response) => {
    return response.data;
  },
  (error) => {
    // 处理401 Unauthorized错误
    if (error.response.status === 401) {
      const authStore = useAuthStore();
      authStore.logout();
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

export default service;

四、应用实例

(一)登录组件
代码语言:javascript
复制
<!-- components/Login.vue -->
<template>
  <div class="login-container">
    <div class="login-form">
      <h2>单点登录系统</h2>
      <BaseInput v-model="username" placeholder="用户名" />
      <BaseInput v-model="password" type="password" placeholder="密码" />
      <BaseButton @click="handleLogin">登录</BaseButton>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useAuthStore } from '@/stores/auth';
import { useRouter } from 'vue-router';

const username = ref('');
const password = ref('');
const authStore = useAuthStore();
const router = useRouter();

const handleLogin = async () => {
  try {
    await authStore.login(username.value, password.value);
    router.push('/dashboard');
  } catch (error) {
    alert(error.message);
  }
};
</script>

<style scoped>
.login-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-color: #f5f5f5;
}

.login-form {
  background-color: white;
  padding: 2rem;
  border-radius: 0.5rem;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  width: 300px;
}

.login-form h2 {
  margin-bottom: 1.5rem;
  text-align: center;
}

.login-form input {
  margin-bottom: 1rem;
  width: 100%;
}

.login-form button {
  width: 100%;
}
</style>
(二)全局导航组件
代码语言:javascript
复制
<!-- components/Navigation.vue -->
<template>
  <nav class="bg-white shadow-md">
    <div class="container mx-auto px-4">
      <div class="flex justify-between items-center h-16">
        <div class="flex items-center">
          <router-link to="/" class="font-bold text-xl">Vue SSO</router-link>
        </div>
        
        <div class="flex items-center space-x-4">
          <router-link to="/" class="text-gray-600 hover:text-primary">首页</router-link>
          
          <div v-if="isAuthenticated" class="flex items-center">
            <span class="mr-2">{{ user?.username || '用户' }}</span>
            <button @click="logout" class="text-gray-600 hover:text-red-500">
              退出
            </button>
          </div>
          
          <router-link to="/login" v-else class="text-gray-600 hover:text-primary">
            登录
          </router-link>
        </div>
      </div>
    </div>
  </nav>
</template>

<script setup>
import { computed } from 'vue';
import { useAuthStore } from '@/stores/auth';

const authStore = useAuthStore();

const isAuthenticated = computed(() => authStore.isAuthenticated);
const user = computed(() => authStore.user);

const logout = () => {
  authStore.logout();
};
</script>

五、高级实现:跨域SSO

(一)CORS配置
代码语言:javascript
复制
// 后端CORS配置示例
app.use(cors({
  origin: 'https://your-frontend-domain.com',
  credentials: true,
}));
(二)跨域Token存储
代码语言:javascript
复制
// 使用HttpOnly Cookie存储Token
document.cookie = `token=${token}; path=/; domain=.your-domain.com; secure; HttpOnly`;
(三)跨域认证流程

六、安全考虑

(一)Token安全
  • 使用HTTPS:防止Token在传输过程中被截获
  • 设置Token过期时间:短期Token减少被盗用风险
  • 使用刷新Token:减少频繁登录,提高用户体验
(二)防止CSRF攻击
  • 使用SameSite属性:限制Cookie在跨站请求中的使用
  • 验证请求来源:检查请求的Referer或Origin头
  • 使用CSRF令牌:在表单或请求中包含CSRF令牌
(三)防止XSS攻击
  • 输入验证:对用户输入进行严格验证和过滤
  • 输出编码:对显示的内容进行适当编码
  • CSP策略:实现内容安全策略,限制页面可以加载的资源

七、总结

通过以上方案,我们实现了一个基于Vue的单点登录系统,包括:

  1. 认证状态管理:使用Pinia存储用户认证状态
  2. 路由守卫:保护需要认证的路由
  3. API拦截器:自动处理Token的添加和验证
  4. 登录组件:实现用户登录功能
  5. 全局导航:根据认证状态显示不同导航项

这个方案可以作为企业级应用的单点登录基础,根据实际需求可以进一步扩展和优化,如支持多因素认证、跨域SSO等高级功能。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-09-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代码教程
  • Vue实现用户单点登录功能技术方案
    • 一、单点登录(SSO)概述
      • (一)什么是单点登录
      • (二)SSO的优势
    • 二、Vue实现SSO的技术方案
      • (一)基于JWT的SSO方案
      • (二)核心技术栈
    • 三、实现步骤
      • (一)创建认证状态管理
      • (二)路由守卫配置
      • (三)API请求拦截器
    • 四、应用实例
      • (一)登录组件
      • (二)全局导航组件
    • 五、高级实现:跨域SSO
      • (一)CORS配置
      • (二)跨域Token存储
      • (三)跨域认证流程
    • 六、安全考虑
      • (一)Token安全
      • (二)防止CSRF攻击
      • (三)防止XSS攻击
    • 七、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档