为了完整起见,我将分享所有内容,甚至是您标记为已完成的部分。
首先,您需要在后端生成 JWT,您可以在没有任何包的情况下简单地执行此操作,但我建议这个包 https://github.com/auth0/node-jsonwebtoken为了那个原因。另外,我将使用 objection.js 来查询数据库,即使您不知道 objection.js 也应该很容易理解
您的登录视图需要像这样发送登录尝试请求
const token = await $fetch('/api/login', {
method: 'post',
body: {
username: this.username,
password: this.password,
},
});
就我而言,它请求 /server/api/ 中的 login.post.ts
import jwt from 'jsonwebtoken';
import { User } from '../models';
export default defineEventHandler(async (event) => {
const body = await useBody(event);
const { id } = await User.query().findOne('username', body.username);
const token: string = await jwt.sign({ id }, 'mysecrettoken');
return token;
});
为了简单起见,我在这里没有查询密码,这取决于您如何生成用户密码。
“mysecrettoken”是您的用户永远不应该知道的令牌,因为他们可以像其他人一样登录。当然这个字符串可以是任何你想要的字符串,越长越好。
现在您的用户获得一个令牌作为响应,应该只是一个简单的字符串。我稍后会写一篇关于如何保存这个以供将来请求的文章。
要使用此令牌发出经过身份验证的请求,您将需要执行如下请求:
$fetch('/api/getauthuser', {
method: 'post',
headers: {
authentication: myJsonWebToken,
},
});
我更喜欢添加一个中间件来更轻松地访问我的 api 端点中的经过身份验证的用户。该中间件名为 setAuth.ts,位于 server/middleware 文件夹内。它看起来像这样:
import jwt from 'jsonwebtoken';
export default defineEventHandler(async (event) => {
if (event.req.headers.authentication) {
event.context.auth = { id: await jwt.verify(event.req.headers.authentication, 'mysecrettoken').id };
}
});
其作用是验证是否传递了身份验证标头,它检查令牌是否有效(使用与您签署 jwt 的相同秘密令牌),如果有效,则将 userId 添加到请求上下文以便于端点访问。
现在,在我的 server/api/getauthuser.ts 端点中可以像这样获取 auth 用户
import { User } from '../models';
export default defineEventHandler(async (event) => {
return await User.query().findById(event.context.auth.id)
});
由于用户无法设置请求上下文,因此您可以确定您的中间件设置了此 auth.id
您现在已经有了基本的身份验证。
我们生成的令牌具有无限的生命周期,这可能不是一个好主意。如果此令牌暴露给其他人,他们将无限期地拥有您的登录信息,进一步解释将超出此答案的范围。
您可以将身份验证令牌保存在 localStorage 中,以便在下一个页面加载时再次访问它。有些人认为这是一种不好的做法,并且更喜欢使用 cookie 来存储它。我会保持简单并使用 localStorage 。
现在,对于用户不应访问登录以外的页面的部分:我在 middleware/auth.global.ts 中设置了一个全局中间件(您也可以执行一个非全局中间件并为特定页面指定它)
auth.global.ts 看起来像这样:
import { useAuthStore } from '../stores';
export default defineNuxtRouteMiddleware(async (to) => {
const authStore = useAuthStore();
if (to.name !== 'Login' && !localStorage.getItem('auth-token')) {
return navigateTo('/login');
} else if (to.name !== 'Login' && !authStore.user) {
authStore.setAuthUser(await $fetch('/api/getauthuser', {
headers: authHeader,
}));
}
});
我使用 pinia 将身份验证用户存储在我的 authStore 中,但前提是本地存储中有身份验证令牌 (jwt)。如果有且尚未获取,请通过 getauthuser 端点获取 auth 用户。如果没有 authtoken 并且该页面不是登录页面,则将用户重定向到该页面