Sapper路由守卫:如何阻止未授权用户访问特定路由?
你当前用onMount的方式虽然能实现跳转,但确实有明显的问题——因为onMount是在组件DOM完全挂载后才触发的,用户会短暂看到页面内容,体验很糟糕,而且纯客户端的校验也容易被绕过,安全性不足。想要在DOM挂载前完成权限校验,Sapper其实有专门的解决方案,下面分两种场景给你详细说:
1. 单个路由的服务器端+客户端前置校验(最推荐,安全且无闪现)
Sapper的路由组件支持导出一个preload函数,这个函数会在服务器端渲染时,以及客户端导航切换页面时,都在组件渲染之前执行,完美符合你要在DOM挂载前处理的需求。
在你的user.svelte里可以这么写:
<script context="module"> // 注意必须加上context="module",这是模块级别的函数 export async function preload(page, session) { // session里的用户信息,是你在服务器端配置好的(后面会说怎么传) if (!session.user) { // 直接重定向到登录页,302是标准的临时重定向状态码 this.redirect(302, '/login'); // 如果是API路由的话,也可以返回401未授权错误 // this.error(401, '你没有访问权限,请先登录'); } } </script> <!-- 这里放你的user组件内容 -->
怎么配置session?
你需要在项目的server.js(或server.ts)里,通过Sapper的中间件把用户认证信息注入到session中,比如从cookie解析用户信息:
import sirv from 'sirv'; import polka from 'polka'; import compression from 'compression'; import * as sapper from '@sapper/server'; const { PORT, NODE_ENV } = process.env; const dev = NODE_ENV === 'development'; polka() .use( compression({ threshold: 0 }), sirv('static', { dev }), sapper.middleware({ // 这里的req和res是服务器端的请求响应对象 session: (req, res) => { // 示例:从cookie中读取用户信息,你可以根据自己的认证方式调整(比如JWT解析) const user = req.cookies?.authenticatedUser ? JSON.parse(req.cookies.authenticatedUser) : null; // 返回的对象会作为session参数传给preload函数 return { user }; } }) ) .listen(PORT, err => { if (err) console.log('服务器启动失败:', err); });
这种方式的优势在于:服务器端直接拦截未授权请求,不会把页面内容返回给用户,安全性拉满;客户端导航时也会在组件渲染前校验,不会有页面闪现的问题。
2. 全局客户端路由守卫(补充方案)
如果你需要统一管理所有需要授权的路由,不想在每个路由组件里写preload,可以在根布局_layout.svelte里监听页面切换事件,全局校验权限:
<script> import { stores } from '@sapper/app'; const { page, session } = stores(); // 当page或session变化时触发校验 $: { const currentPath = $page.path; // 定义所有需要授权的路由 const protectedRoutes = ['/user', '/dashboard', '/profile']; // 如果当前路由需要授权且用户未登录,直接跳转登录页 if (protectedRoutes.includes(currentPath) && !$session.user) { window.location.href = '/login'; } } </script> <!-- 根布局的内容,比如导航栏、页脚等 --> <nav> <!-- 你的导航内容 --> </nav> <main> <slot /> <!-- 子路由组件会渲染在这里 --> </main>
不过要注意,这种方式是纯客户端的校验,用户可以通过禁用JavaScript绕过,所以只能作为服务器端校验的补充,不能单独用来做权限控制。
最后再总结下
你的当前方案的核心问题是时机太晚(DOM挂载后才执行),而preload函数正好解决了这个问题——它在组件渲染前就会运行,而且支持服务器端和客户端双重校验,既解决了页面闪现的问题,又保证了安全性,这才是Sapper中处理路由权限的标准方式。
内容的提问来源于stack exchange,提问作者Raold

