使用钩子在Svelte中安全身份验证
#javascript #教程 #svelte #authentication

如果您需要阻止对应用程序特定部分的访问,则大多数新的Svelte开发人员(包括我自己)立即跳入+layout.svelte文件以开始处理请求。不幸的是,这会导致一些很难修复的副作用。解决此问题的方法是使用Magic hooks.server.js文件!

hooks.server.js文件在呈现之前截取所有 dynamic 路由。这是一个重要的区别,因为Prerendered页面不会流过此过程(这可能会导致很多令人沮丧的调试)。解决此问题的最简单方法是在您的admin路由文件夹中创建一个空白的+layout.server.js文件。一个例子可能是这样:

├─ src
│  ├─ routes
|  |  ├─ admin (all authenticated pages)
|  |  |  ├─ +page.svelte (main authenticated page)
|  |  |  ├─ +layout.server.js
│  │  ├─ +page.svelte (unauthenticated homepage)
│  ├─ hooks.server.js
// /src/routes/admin/+layout.server.js
export async function load() {}

这里的魔术是,现在您的admin文件夹中的每个页面都不会被预先列入。这会迫使该目录中的任何请求流经hooks.server.js文件。

现在我们已经设置了,让我们看一下hooks.server.js文件。

我们需要做的第一件事是设置handle()函数。这将拦截所有请求,这是我们可以进行检查的地方。

// hooks.server.js
export const handle = async({event, resolve}) => {
  const response = await resolve(event);

  return response;
}

在我们继续之前,让我们查看通过handle()函数传递的两个属性:eventresolve

事件包含与文件请求有关的所有信息。这包括用户的cookie,浏览器HTTP标头和特定请求的URL。您可以在此处阅读更多Indepth文档:SvelteKit Hooks

第二项resolve是创建完成HTML的功能。当我们根据用户的cookie修改主题值从光线变为黑暗时,这将在以后的教程中很有用。目前,我们将重点关注身份验证。

我们的handle()函数是await resolve(event)调用。这是一件Sveltekit的东西,本质上告诉服务器在将HTML发送给客户端之前就可以构建HTML了。返回该response值以正常方式呈现页面。

身份验证设置

在我们的hooks.server.js文件中,我们可以获取当前请求的路径名,并检查用户是否试图访问我们的管理路线。我们还可以吸引cookie来检查我们的验证令牌。在此示例中,我们将仅使用示例auth令牌,但是您可以将其交换为您要使用的任何身份验证库SDK。

// hooks.server.js
export const handle = async({event, resolve}) => {
  const requestedPath = event.url.pathname;
  const cookies = event.cookies;

  // Auth check will go here

  const response = await resolve(event);

  return response;
}

现在我们有了URL和Cookie,我们可以进行验证。

// hooks.server.js
export const handle = async({event, resolve}) => {
  const requestedPath = event.url.pathname;
  const cookies = event.cookies;

  // Auth check
  const isTokenValid = validateTokenFunction(cookies);

  const response = await resolve(event);

  return response;
}

const validateTokenFunction = (cookies) => {
  // This will look for the user's cookies and see if the auth token exists
  const currentToken = cookies.get("auth-token");

  // If the auth token is valid (i.e. matches the string 123), then it will return `true`.
  return currentToken === "123";
}

现在,我们知道我们的auth令牌是否有效,我们可以将其与当前路线进行比较:

import {redirect} from '@sveltejs/kit';

// hooks.server.js
export const handle = async({event, resolve}) => {
  const requestedPath = event.url.pathname;
  const cookies = event.cookies;

  // Auth check
  const isTokenValid = validateTokenFunction(cookies);

  // Restrict all routes under /admin
  if(currentPath.includes("/admin")) {
    if(!isTokenValid) {
      throw redirect(303, "/");
    }
  }

  const response = await resolve(event);

  return response;
}

const validateTokenFunction = (cookies) => {
  // This will look for the user's cookies and see if the auth token exists
  const currentToken = cookies.get("auth-token");

  // If the auth token is valid (i.e. matches the string 123), then it will return `true`.
  return currentToken === "123";
}

请注意,我们导入了Svelte函数redirect。这将使我们能够将用户发送到 之前的其他位置。这是防止管理员内容不窥视眼睛的最安全方法。

您可以扩展此if语句,以包括有关用户角色或其他类型请求的其他检查。这样,您就可以通过添加其他检查来拥有一个具有多个用户访问的管理面板。

这样,您的Sveltekit应用程序得到了保护。尝试一下,看看该网站将不允许您访问/admin页面,而没有称为auth-token的cookie将其设置为123

其他改进

您可能需要将validateToken()函数移动到您的/src/lib/server文件夹中,以便每次访问路由时都不会重新创建它。我通常在其中创建一个名为authentication.js的文件,以容纳所有类型的认证功能。

来源

Huntabyte: Protect SvelteKit Routes with Hooks大喊他们的教程。他们的版本在打字稿中,我的版本在JavaScript中。