本文讲解前端通过简单的方式实现一个基本的登录注册验证功能。在后端,使用 session 表来存储会话信息,并让前端的 localStorage
存储 sessionId
。通过 sessionId
可以在 session 表中获取用户的信息。此外,还利用 session 表实现了 GitHub 的 OAuth2 第三方登录。
在本项目中,我们使用 Vue 作为前端框架,通过与后端 API 交互来管理用户的会话状态。
sessionId
,前端将其存储在localStorage
中。sessionId
,以便后端能够验证用户的身份。GitHub
登录按钮后,前端会重定向到GitHub
的授权页面。用户授权后,GitHub
重定向回我们的网站,并附带授权码。前端将授权码发送到后端服务器以换取访问令牌。后端地址:springboot-session-github-oauth
前端地址:vite-session-github-oauth
路由守卫
路由守卫确保只有经过身份验证的用户才能访问某些页面。
// 添加全局前置守卫 router.beforeEach(async (to, from, next) => { if (to.name == "Home") { const sessionId = ref(""); const sessionIdFromUrl = to.query.sessionId as string; if (sessionIdFromUrl) { sessionId.value = sessionIdFromUrl; localStorage.setItem('sessionId', sessionIdFromUrl); } else if (localStorage.getItem('sessionId')) { sessionId.value = localStorage.getItem('sessionId') || ''; } if (sessionId.value == '') { // 没有 sessionId,重定向到登录页面 return next({ name: 'Login' }); } else { try { // 验证 sessionId 是否有效 const response = await axios.get('http://localhost:8080/auth/home', { params: { sessionId: sessionId.value } }); if (response.data && response.data.data) { // 如果 username 存在,则 sessionId 有效 localStorage.setItem('username', response.data.data); next(); } else { // 如果无效,清除 localStorage 并重定向到登录页面 localStorage.removeItem('sessionId'); next({ name: 'Login' }); } } catch (error) { console.error('验证 sessionId 失败:', error); localStorage.removeItem('sessionId'); next({ name: 'Login' }); } } } else { // 如果目标路由是登录页面,直接继续导航 next(); } });
代码设计
Login.vue
<script setup lang="ts"> import { ref } from 'vue'; import axios from 'axios'; import router from '../routes.ts'; const username = ref(''); const password = ref(''); const handleLogin = async () => { try { const response = await axios.post('http://localhost:8080/auth/login',{ username: username.value, password: password.value }); localStorage.setItem('sessionId', response.data.data); console.log(response.data.data); await router.push('/home'); } catch (error) { console.log(error); } } const handleLoginByGithub = () => { window.location.href = 'http://localhost:8080/oauth/authorize'; } </script> <template> <div class="flex justify-center items-center min-h-screen bg-gray-2"> <div class="w-full max-w-md p-8 space-y-8 bg-white rounded-lg shadow-lg"> <h2 class="text-2xl font-bold text-center text-gray-800"> 客户端登录(session登录) </h2> <form class="space-y-6" @submit.prevent> <div> <label for="username" class="block text-sm font-medium text-gray-700"> 用户名 </label> <input v-model="username" id="username" name="username" type="text" required class="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" /> </div> <div> <label for="password" class="block text-sm font-medium text-gray-700"> 密码 </label> <input v-model="password" id="password" name="password" type="password" required class="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" /> </div> <div class="flex justify-end"> <router-link to="/register"> 还没有账号,点击注册 </router-link> </div> <div> <button type="submit" class="w-full px-4 py-2 font-semibold text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" @click="handleLoginByGithub"> 使用GiHub登录 </button> </div> <div> <button type="submit" class="w-full px-4 py-2 font-semibold text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" @click="handleLogin"> 登录 </button> </div> </form> </div> </div> </template> <style scoped></style>
Register.vue
<script setup lang="ts"> import { ref } from 'vue'; import axios from 'axios'; import router from '../routes'; const username = ref(''); const password = ref(''); const handleRegister = async () => { try { const response = await axios.post('http://localhost:8080/auth/register', { username: username.value, password: password.value, }); console.log(response.data); localStorage.setItem('sessionId', response.data.data); await router.push('/home'); } catch (error) { console.log(error); } }; </script> <template> <div class="flex justify-center items-center min-h-screen bg-gray-100"> <div class="w-full max-w-md p-8 space-y-8 bg-white rounded-lg shadow-lg"> <h2 class="text-2xl font-bold text-center text-gray-800"> 客户端注册(session注册) </h2> <form class="space-y-6" @submit.prevent="handleRegister"> <div> <label for="username" class="block text-sm font-medium text-gray-700"> 用户名 </label> <input v-model="username" id="username" name="username" type="text" required class="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" /> </div> <div> <label for="password" class="block text-sm font-medium text-gray-700"> 密码 </label> <input v-model="password" id="password" name="password" type="password" required class="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" /> </div> <div class="flex justify-end"> <router-link to="/login"> 已有账号?点击登录 </router-link> </div> <div> <button type="submit" class="w-full px-4 py-2 font-semibold text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" @click.prevent="handleRegister"> 注册 </button> </div> </form> </div> </div> </template> <style scoped></style>
Home.vue
<script setup lang="ts"> import { onMounted, ref } from 'vue'; import axios from 'axios'; import router from '../routes'; import { ElMessage } from 'element-plus'; const username = ref(''); const sessionId = ref(''); const state = ref(''); const showPasswordDialog = ref(false); const newPassword = ref(''); const confirmPassword = ref(''); // New ref for confirming password username.value = localStorage.getItem('username'); sessionId.value = localStorage.getItem('sessionId'); console.log(sessionId.value); const handleState = async () => { try { const response = await axios.get('http://localhost:8080/user/state', { params: { sessionId: sessionId.value } }); state.value = response.data.data; } catch (error) { console.log(error); } }; const handleAddPassword = async () => { if (newPassword.value !== confirmPassword.value) { ElMessage.error('Passwords do not match'); return; } try { const response = await axios.post('http://localhost:8080/user/addPassword', { password: newPassword.value }, { params: { sessionId: sessionId.value, } }); console.log(response.data); if (response.data.status === 'OK') { ElMessage.success('Password added successfully'); showPasswordDialog.value = false; newPassword.value = ''; confirmPassword.value = ''; // Reset password fields } else { ElMessage.error('Failed to add password'); } } catch (error) { console.log(error); ElMessage.error('An error occurred while adding the password'); } }; const handleLoginByGitHub = async () => { window.location.href = 'http://localhost:8082/oauth/authorize?sessionId=' + sessionId.value; } const handleLogout = async () => { try { const response = await axios.get('http://localhost:8080/auth/logout', { params: { sessionId: sessionId.value } }); localStorage.removeItem('sessionId'); sessionId.value = ''; await router.push('/login'); console.log(response.data); } catch (error) { console.log(error); } }; // Execute on component mount onMounted(() => { handleState(); }); </script> <template> <div class="flex justify-center items-center min-h-screen bg-gray-2"> <div class="w-full max-w-md p-8 space-y-8 bg-white rounded-lg shadow-lg"> <h2 class="text-2xl font-bold text-center text-gray-800"> 使用Session登录成功 </h2> <p class="text-center text-gray-600"> 欢迎回来, {{ username }} </p> <div v-if="state == 'password'" class="flex justify-end"> <button class="px-4 py-2 font-semibold text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" @click="showPasswordDialog = true"> 添加密码 </button> </div> <div v-else-if="state == 'githubLoginName'" class="flex justify-end"> <button class="px-4 py-2 font-semibold text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" @click="handleLoginByGitHub"> 绑定github账号 </button> </div> <div class="flex justify-end"> <button class="px-4 py-2 font-semibold text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" @click="handleLogout"> 退出 </button> </div> </div> </div> <!-- Password Dialog --> <el-dialog v-model="showPasswordDialog" title="添加密码" width="500" draggable> <div class="space-y-4"> <!-- New Password --> <div class="flex items-center space-x-4"> <label for="newPassword" class="text-sm font-medium text-gray-700"> 输入密码 </label> <input v-model="newPassword" id="newPassword" name="newPassword" type="password" required class="w-5/6 px-4 py-2 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" /> </div> <!-- Confirm Password --> <div class="flex items-center space-x-4"> <label for="confirmPassword" class="text-sm font-medium text-gray-700"> 确认密码 </label> <input v-model="confirmPassword" id="confirmPassword" name="confirmPassword" type="password" required class="w-5/6 px-4 py-2 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500" /> </div> </div> <template #footer> <div class="dialog-footer"> <el-button @click="showPasswordDialog = false">取消</el-button> <el-button type="primary" @click="handleAddPassword">确定</el-button> </div> </template> </el-dialog> </template> <style scoped></style>
到此这篇关于vue基于session和github-oauth2实现登录注册验证的文章就介绍到这了,更多相关vue登录注册验证内容请搜索插件窝以前的文章或继续浏览下面的相关文章希望大家以后多多支持插件窝!