You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sapper路由守卫:如何阻止未授权用户访问特定路由?

阻止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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:45:17