SAML SSO:Next.js 应用身份验证难题中缺失的一环🧩
了解如何完善登录流程,实现无缝登录
目录
TL;DR:
完成本教程后,您将为您的 Next.js 应用实现功能齐全的 SAML 单点登录集成。🚀
流程如下:
- 逐步讲解整个过程,并提供代码示例。
在你走得太远之前,最好先找出你的使用场景。
如果您希望通过为客户实施 SAML 单点登录 (SSO) 身份验证来增强 Next.js 应用的安全性和用户体验,那么您来对地方了。让我们开始吧!
单点登录简述
单点登录 (SSO) 简化了用户身份验证,允许用户使用一组凭据登录一次,即可访问多个内部应用程序或服务。
身份验证与授权
我想快速区分一下单点登录 (SSO) 身份验证和授权之间的区别,因为它们在用户访问控制领域有着不同但又相互关联的目的。SSO 身份验证主要侧重于验证用户身份,确保用户是其声称的本人,并授予其访问内部系统、应用程序或服务的权限。
授权是指定义并授予已认证用户特定权限和访问权限的过程,明确规定他们在系统或应用程序中可以或不可以执行哪些操作或访问哪些资源。
现在,您可能想知道如何为您的初创公司/中小企业/企业用户将这种无缝的单点登录 (SSO) 体验带到您的 Next.js 应用中。这正是我们接下来要构建的内容,并且我们有一些资源可以帮助您完成这项工作。
为了更好地理解其实现方式,您可以查看以下两个 GitHub 代码库。
-
BoxyHQ 的 SAML SSO - 主要单点登录资源
-
Next.js SAML SSO 集成的源代码
将 SAML 单点登录集成到您的应用程序中
将 SAML 单点登录 (SSO) 集成到您的应用程序中涉及以下关键步骤:
-
配置 SAML 单点登录:
此步骤允许您的租户为其用户配置 SAML 连接。请务必查看以下指南,以深入了解此过程:
使用 SAML 单点登录进行身份验证:
添加 SAML 连接后,您的应用可以利用此 SAML 连接,通过 SAML Jackson 启动 SSO 身份验证流程。以下章节将重点介绍 SSO 身份验证方面的内容。
没错,你没听错——SAML Jackson 😉
对了,如果你访问⬆️SAML Jackson代码库⬆️,能不能给我点个赞?⭐
让我们回到正题,继续编程吧!🧑💻
安装 SAML Jackson
要开始使用 SAML Jackson,请使用 Node 包管理器 (NPM) 将其添加到项目的依赖项中:
npm i --save @boxyhq/saml-jackson
设置 SAML Jackson
接下来,您需要配置 SAML Jackson,使其与您的 Next.js 应用无缝协作。这涉及到修改环境变量(.env 文件)并创建 Jackson 配置文件。
title=".env"
NEXTAUTH_URL=https://your-app.com
NEXTAUTH_SECRET= #A random string is used to hash tokens, sign/encrypt cookies, and generate cryptographic keys.
在继续之前,我们需要为上面文件中显示的NEXTAUTH_SECRET生成一个随机字符串。这可以通过下载OpenSSL并在终端中输入以下命令.env轻松完成,该命令将生成一个 32 个字符的随机密钥。openssl rand -base64 24
接下来,我们创建一个新文件lib/jackson.ts
import jackson, {
type IOAuthController,
type JacksonOption,
} from "@boxyhq/saml-jackson";
const samlAudience = "https://saml.boxyhq.com";
const samlPath = "/api/oauth/saml";
const opts: JacksonOption = {
externalUrl: `${process.env.NEXTAUTH_URL}`,
samlAudience,
samlPath,
db: {
engine: "sql",
type: "postgres",
url: "postgres://postgres:postgres@localhost:5432/postgres",
},
};
let oauthController: IOAuthController;
const g = global as any;
export default async function init() {
if (!g.oauthController) {
const ret = await jackson(opts);
oauthController = ret.oauthController;
g.oauthController = oauthController;
} else {
oauthController = g.oauthController;
}
return {
oauthController,
};
}
需要特别说明的是:这samlPath是身份提供商在验证用户身份后 POST SAML 响应的位置。
简而言之,我们来分析一下这段代码的功能。
首先,我们确保整个应用程序中只创建和使用一个 Jackson 控制器实例。每当需要访问 Jackson OAuth 控制器时,只需将该jackson实例导入到需要它的文件中即可。
NextAuth.js 集成
我们将使用NextAuth.js进行身份验证,这是一个专为 Next.js 应用程序设计的全面的开源身份验证解决方案。接下来,我们来安装它。 (注):我会添加NextAuth 文档
中关于 SAML Jackson 的链接,供您参考。
npm i --save next-auth
NextAuth 内置了 BoxyHQ SAMLboxyhq-saml作为 SAML 身份验证提供程序。我们将使用此提供程序对用户进行身份验证。
现在我们将创建一个新文件pages/api/auth/[...nextauth].ts
import NextAuth, { type NextAuthOptions } from 'next-auth';
import BoxyHQSAMLProvider from 'next-auth/providers/boxyhq-saml';
export const authOptions: NextAuthOptions = {
providers: [
BoxyHQSAMLProvider({
authorization: { params: { scope: '' } },
issuer: `${process.env.NEXTAUTH_URL}`,
clientId: 'dummy',
clientSecret: 'dummy',
httpOptions: {
timeout: 30000,
},
}),
],
session: {
strategy: 'jwt',
},
};
export default NextAuth(authOptions);
我们来看看这里发生了什么。
这段代码本质上是为你的应用程序提供了一组指令,用于安全地处理用户登录。该authOptions对象定义了身份验证提供程序以及任何其他相关设置,例如会话策略。然后,它导出 NextAuth 实例,并将这些身份验证选项传递给 Next.js 应用程序,从而允许 Next.js 应用程序利用指定的身份验证提供程序和策略进行用户身份验证和会话管理。
发出身份验证请求
现在,让我们添加一条路由,通过将用户重定向到其配置的身份提供程序来启动 SAML SSO 的身份验证流程。
我们把这个文件叫做pages/api/oauth/authorize.t
import type { NextApiRequest, NextApiResponse } from "next";
import type { OAuthReq } from "@boxyhq/saml-jackson";
import jackson from "../../../../lib/jackson";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { oauthController } = await jackson();
const { redirect_url } = await oauthController.authorize(
req.query as unknown as OAuthReq
);
return res.redirect(302, redirect_url as string);
}
收到 SAML 响应
身份验证成功后,身份提供商 (IdP) 会将 SAML 响应 POST 到断言使用者服务 (ACS) URL。我们需要创建一个路由来处理此响应。
新文件pages/api/oauth/saml.ts
import type { NextApiRequest, NextApiResponse } from "next";
import jackson from "../../../../lib/jackson";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { oauthController } = await jackson();
const { RelayState, SAMLResponse } = req.body;
const { redirect_url } = await oauthController.samlResponse({
RelayState,
SAMLResponse,
});
return res.redirect(302, redirect_url as string);
}
请求访问令牌
接下来,我们需要一个路由来接收身份验证后的回调。NextAuth 会请求一个回调access token,并传递授权码以及身份验证详细信息,包括grant_type、redirect_uri和code_verifier。
我们现在想要创建一个文件pages/api/oauth/token.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '../../../../lib/jackson';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { oauthController } = await jackson();
const response = await oauthController.token(req.body);
return res.json(response);
}
获取用户个人资料
获取到身份验证信息后access_token,NextAuth 可以使用该信息从身份提供商处检索用户配置文件。userInfo如果授权有效,该方法将返回包含用户配置文件的响应。
我们需要一份新文件pages/api/oauth/userinfo.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '../../../../lib/jackson';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { oauthController } = await jackson();
const authHeader = req.headers['authorization'];
if (!authHeader) {
throw new Error('Unauthorized');
}
const token = authHeader.split(' ')[1];
const user = await oauthController.userInfo(token);
return res.json(user);
}
回复将包含用户信息,包括他们的 ID、电子邮件、名字、姓氏等。
{
"id":"<id from the Identity Provider>",
"email": "jackson@coolstartup.com",
"firstName": "SAML",
"lastName": "Jackson",
"requested": {
"tenant": "<tenant>",
"product": "<product>",
"client_id": "<client_id>",
"state": "<state>"
},
"raw": {
...
}
}
用户身份验证
最后,从身份提供商处获取用户信息后,您可以确定该用户是否存在于您的应用程序中,并据此进行身份验证。如果用户不存在,您可以在数据库中创建新记录并将其添加进去。
启动 OAuth 登录流程
为了启动我们应用程序的 OAuth 登录流程,我们将使用 NextAuth 的signIn方法并向boxyhq-saml提供商进行身份验证。
你可以通过第三个参数将tenantandproduct作为附加参数传递给端点。/api/oauth/authorizesignIn()
请
确保为租户和产品组合添加有效的 SAML 连接。否则,身份验证将失败。点击此处
了解如何创建 SAML 连接 。
要使此示例应用程序正常工作,您需要先为租户boxyhq.com和产品添加 SAML 连接saml-demo.boxyhq.com,然后才能对用户进行身份验证。
让我们通过创建来实现这一点pages/login.tsx
import type { NextPage } from 'next';
import { useSession, signIn } from 'next-auth/react';
const Login: NextPage = () => {
const { data: session, status } = useSession();
if (status === 'loading') {
return <>Loading...</>;
}
if (status === 'authenticated') {
return <>Authenticated</>;
}
// Starts OAuth sign-in flow
signIn('boxyhq-saml', undefined, {
tenant: 'boxyhq.com',
product: 'saml-demo.boxyhq.com',
});
return <>Unauthenticated</>;
};
export default Login;
恭喜!
让我们花点时间回顾一下我们学到了什么🥇
🎬 我们首先探索了单点登录 (SSO) 的世界,以及它为您的 Next.js 应用程序进行身份验证的变革性力量。
🔐 SSO 简化了用户身份验证,允许用户通过一次登录访问多个内部应用程序,这对于安全性和用户体验都至关重要。
💡 我们一直致力于实施基于 SAML 的 SSO,这是一个强大且广泛使用的协议。
🗺️ 然后我们一步一步地讲解了整个过程,从配置 SAML 单点登录到在您的应用程序中验证用户身份。
📚 我们学习了如何设置 SAML Jackson 单点登录 (SSO)、如何将其与 NextAuth.js 集成,以及如何通过精心编写的代码片段实现 SSO 功能。每个部分都让您离为客户打造无缝的 SSO 体验更近了一步。
🚀 告别密码疲劳,拥抱 Next.js 应用的未来身份验证方式。借助 SAML 单点登录 (SSO),您可以简化登录流程、增强安全性并提升用户满意度。我们现在可以自豪地说,我们已经成功开启了轻松身份验证的大门,并为您的应用带来了更美好的未来!
社区
如果您在开发过程中有任何疑问或遇到困难,请加入我们的BoxyHQ Discord 开发者社区。
文章来源:https://dev.to/nathan_tarbert/saml-sso-the-missing-piece-in-your-nextjs-apps-authentication-puzzle-3h9f



