如何在使用@auth0/ Nextjs -auth0的Nextjs应用程序中使用auth0授权后重定向到起点



我目前使用auth0在Next.js应用程序中验证用户。

我正在使用@auth0/nextjs-auth0 SDK并遵循文档。

然而,我很难弄清楚如何根据用户访问登录表单的页面在登录后动态重定向用户。

在我目前试图构建的应用程序中,用户可以从"/"这是主页登录,并从导航栏元素在"/浏览"。但是,在登录后,它总是重定向回"/",而我想重定向用户到"/browse"或"/browse/[id],如果这是他们开始登录过程的地方。

我试过使用https://community.auth0.com/t/redirecting-to-another-page-other-than-using-nextjs-auth0/66920作为指南,但这种方法只允许我重定向到一个预定义的路由。我想知道如何使重定向URL动态。

提前感谢!

编辑:我已经设法找到了一个解决方案,现在通过挖掘到req对象,并将returnTo值设置为"referer"。

import { handleAuth, handleLogin } from '@auth0/nextjs-auth0';
const getLoginState = (req, loginOptions) => {
return {
returnTo: req.headers.referer
};
};
export default handleAuth({
async login(req, res) {
try {
await handleLogin(req, res, { getLoginState });
} catch (err) {
res.status(err.status ?? 500).end(err.message)
}
}
});

到目前为止,我没有看到任何明显的问题,但我不完全确定这种方法是否有任何缺点,所以我将感谢任何反馈。

这个怎么样?

步骤1:初始化Auth0 SDK

https://auth0.github.io/nextjs-auth0/modules/instance.html initauth0

# /lib/auth0,js
import { initAuth0 } from "@auth0/nextjs-auth0";
export default initAuth0({
secret: process.env.SESSION_COOKIE_SECRET,
issuerBaseURL: process.env.NEXT_PUBLIC_AUTH0_DOMAIN,
baseURL: process.env.NEXT_PUBLIC_BASE_URL,
clientID: process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
routes: {
callback:
process.env.NEXT_PUBLIC_REDIRECT_URI ||
"http://localhost:3000/api/auth/callback",
postLogoutRedirect:
process.env.NEXT_PUBLIC_POST_LOGOUT_REDIRECT_URI ||
"http://localhost:3000",
},
authorizationParams: {
response_type: "code",
scope: process.env.NEXT_PUBLIC_AUTH0_SCOPE,
},
session: {
absoluteDuration: process.env.SESSION_COOKIE_LIFETIME,
},
});

步骤2:配置登录

https://auth0.github.io/nextjs-auth0/modules/handlers_login.html handlelogin

https://auth0.github.io/nextjs-auth0/interfaces/handlers_login.loginoptions.html区

# /pages/api/auth/login.js
import auth0 from "../../../lib/auth0";
export default async function login(req, res) {
let options = {
returnTo: 'http://localhost:3000/dashboard'
}
try {
await auth0.handleLogin(req, res, options);
} catch (error) {
console.error(error);
res.status(error.status || 500).end(error.message);
}
}

现在您将在成功验证后进入仪表板页面。

步骤3:有用的完整性检查

用以下内容创建/pages/api/auth/callback.js

import auth0 from "../../../lib/auth0";
const afterCallback = (req, res, session, state) => {
// console.log(session)
console.log(state)
return session
};
export default async function callback(req, res) {
try {
console.log(auth0)
await auth0.handleCallback(req, res, { afterCallback });
} catch (error) {
console.error(error);
res.status(error.status || 500).end(error.message);
}
}

尝试登录并在控制台中查找状态,

{ returnTo: 'http://localhost:3000/dashboard' }

干杯!

这个库有一个内置的页面保护,会自动将浏览器重定向到保存的loginUrl(默认是/api/auth/login,但你可以在<UserProvider loginUrl={*your_custom_login_path*}>中自定义它。

所以import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";

export default withPageAuthRequired(*your_page_component*)

浏览器将在其重定向中获得一个查询参数returnTo,您可以在自定义重定向中处理该参数,否则,如果您使用默认的auth0进程,它将在成功登录后自动重定向到此路径。

我觉得这是一个非常干净的工作代码。

一旦会话结束,用户将首先注销(/api/auth/logout),因此我们将在这里捕获lastVisited页面,发布该用户将被重定向到注销重定向页面(阅读此处的替代注销)。

因为,在大多数项目中,用户将返回到基础url (localhost:3000),我们可以再次捕获lastVisited,它将在handleLogin中自动作为returnTo参数传递。如果你有一个自定义的登录处理程序,确保你没有改变returnTo参数,一切都应该正常工作。

步骤1

在注销中间件中捕获lastVisited

在handleLogout中间件中使用当前页面引用头捕获lastVisited页面,并作为查询参数传递。

// pages/api/auth/[auth0].ts
import { handleAuth, handleLogout } from 'lib/auth0'
export default handleAuth({
async logout(req, res) {
try {
let callingUrl
if (req.headers.referer) {
callingUrl = new URL(req.headers.referer)
}
await handleLogout(req, res, { returnTo: `/?lastVisited=${callingUrl?.pathname}` })
} catch (error) {
// TODO: Need to work on the 401, 404 errors pages
res.writeHead(401, { Location: `custom-error-page` })
res.end()
}
},
})
步骤2

从base URL的查询中获取lastVisited

现在我们有了想要重定向的页面,我们可以使用req.querygetServerSideProps中捕获它,并且它将自动作为returnTo参数传递到/loginAPI中。

// pages/index.tsx
import { ROUTES } from 'constants/routes'
import { GetServerSideProps, NextPage } from 'next'
const HomePage: NextPage = () => {
return <><This is the base url</>
}
export const getServerSideProps: GetServerSideProps = async ({ query }) => {
// Redirect based on the parameters or query
const destination = query?.lastVisited?.toString() || ROUTES.DASHBOARD
return {
redirect: {
destination,
permanent: false,
},
}
}
export default HomePage

希望这有助于节省一些时间。因为我确实为这个问题挠头了好几个小时。