Next.js
使用 App Router 和 TypeScript SDK 接入
Next.js 接入
Next.js App Router 必须在 Route Handler 或 Server Component 的服务端边界接入 IWish Auth。Client Secret、PKCE verifier 和 opaque App Session 不进入客户端组件。
配置
import { createIWishAuth } from "@iwish/auth-sdk/next";
export const auth = createIWishAuth({
apiUrl: process.env.IWISH_AUTH_API_URL!,
portalUrl: process.env.IWISH_AUTH_PORTAL_URL!,
appKey: "reporting",
clientId: process.env.IWISH_AUTH_CLIENT_ID!,
clientSecret: process.env.IWISH_AUTH_CLIENT_SECRET!,
redirectUri: "https://reporting-staging.example.com/auth/callback"
});
分别创建 login、callback 和 logout Route Handler,直接返回 beginLogin、handleCallback 和 logout 的 Response。SDK 自动使用 PKCE,并把 App Session 写入 HttpOnly、SameSite=Lax Cookie;HTTPS 环境同时启用 Secure。
受保护接口
export async function GET(request: Request) {
const session = await auth.requireAppAccess(request);
const member = await db.appMember.findUnique({ where: { iwishAuthUserId: session.user.id } });
if (!member || member.status !== "active") {
return Response.json({ error: "local_member_required" }, { status: 403 });
}
const allowed = await localPermissions.has(member.id, "report.read");
if (!allowed) return Response.json({ error: "local_permission_denied" }, { status: 403 });
return Response.json(await loadReports({ member, clientAssignments: session.clientAssignments }));
}
requireAppAccess 验证 session、当前 App、组织开通和 Auth 生命周期;本地成员与 report.read 由业务 App 自己检查。不要使用已返回 410 的 requirePermission。
Server Component
Server Component 可以通过受保护的服务端函数读取 session,但不要把 opaque token、Client Secret 或完整员工敏感字段传给 Client Component。只序列化页面确实需要的展示字段。缓存 key 必须至少包含 iwish_auth_user_id、App、本地授权版本和必要的数据范围;收到停用或客户团队 Webhook 后清理相关缓存。
验收
验证 callback 精确匹配、跨 App cookie 被拒绝、无本地成员 403、本地角色不足 403、assignment 不自动授权、飞书离职后旧 session 失效、外部邮箱账号仍需本地成员。production 不得配置通配 callback、宽泛 Cookie Domain 或浏览器可读 session cookie。