You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 15部署Next-Auth Steam认证时遇NextApiRequest类型错误

解决Next.js 15 + NextAuth + Steam认证构建时的类型错误问题

问题核心

你遇到的类型错误是因为Next.js 15的App Router API路由要求使用Web标准Request/NextRequest作为处理函数参数,而你的代码中使用了Pages Router专属的NextApiRequest/NextApiResponse。同时next-auth-steam@0.3.0是为Pages Router设计的,与App Router的请求模型不兼容。

解决方案

直接手动实现Steam的OpenID认证逻辑(替代next-auth-steam),适配App Router的类型要求,以下是修改后的完整代码:

// src/app/api/auth/[...nextauth]/route.ts
import NextAuth, { NextAuthOptions } from 'next-auth';
import { OAuthConfig, OAuthUserConfig } from 'next-auth/providers/oauth';
import { NextRequest } from 'next/server';

// 定义Steam用户资料类型
interface SteamProfile {
  steamid: string;
  personaname: string;
  avatarfull: string;
  personastate: number;
  // 其他可选字段可根据需求添加
}

// 手动实现Steam OpenID Provider
const SteamProvider = (options: OAuthUserConfig<SteamProfile>): OAuthConfig<SteamProfile> => ({
  id: 'steam',
  name: 'Steam',
  type: 'oauth',
  authorization: {
    url: 'https://steamcommunity.com/openid/login',
    params: {
      openid.mode: 'checkid_setup',
      openid.return_to: options.callbackUrl,
      openid.realm: options.callbackUrl.split('/api')[0],
      openid.ns: 'http://specs.openid.net/auth/2.0',
    },
  },
  token: {
    url: 'https://steamcommunity.com/openid/login',
    async request({ params }) {
      // 验证Steam的OpenID响应
      const response = await fetch('https://steamcommunity.com/openid/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: new URLSearchParams({
          ...params,
          openid.mode: 'check_authentication',
        }),
      });
      const responseText = await response.text();
      
      if (!responseText.includes('is_valid:true')) throw new Error('Steam认证失败');
      
      // 提取Steam ID
      const steamIdMatch = responseText.match(/openid.identity:https:\/\/steamcommunity\.com\/openid\/id\/(\d+)/);
      if (!steamIdMatch) throw new Error('无法提取Steam ID');
      const steamId = steamIdMatch[1];

      // 获取用户公开资料
      const profileRes = await fetch(
        `https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?key=${process.env.STEAM_API_KEY}&steamids=${steamId}`
      );
      const profileData = await profileRes.json();
      const userProfile = profileData.response.players[0];

      return {
        tokens: { access_token: steamId },
        profile: userProfile,
      };
    },
  },
  userinfo: {
    url: 'https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/',
    async request({ tokens }) {
      const res = await fetch(
        `${this.userinfo.url}?key=${process.env.STEAM_API_KEY}&steamids=${tokens.access_token}`
      );
      const data = await res.json();
      return data.response.players[0];
    },
  },
  profile(profile) {
    return {
      id: profile.steamid,
      name: profile.personaname,
      image: profile.avatarfull,
      personastate: profile.personastate,
    };
  },
  ...options,
});

// 扩展NextAuth类型
declare module 'next-auth' {
  interface Session {
    user: {
      id: string;
      email?: string;
      image?: string;
      name?: string;
      personastate?: string;
      player_id: string;
      steam_id: string;
    };
  }

  interface JWT {
    personastate?: number;
    picture?: string;
  }
}

// 环境变量校验
if (!process.env.STEAM_API_KEY) throw new Error("必须配置STEAM_API_KEY环境变量");

// NextAuth配置
const authOptions: NextAuthOptions = {
  providers: [
    SteamProvider({
      callbackUrl: `${process.env.NEXTAUTH_URL}/api/auth/callback/steam`,
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
  callbacks: {
    async session({ session, token }) {
      session.user.steam_id = token.sub!;
      session.user.player_id = token.sub!;
      session.user.id = token.sub!;
      session.user.name = token.name ?? session.user.name;
      session.user.personastate = token.personastate !== undefined ? String(token.personastate) : 'Offline';
      session.user.image = token.picture ?? session.user.image;
      return session;
    },
    async jwt({ token, user }) {
      if (user) {
        token.personastate = (user as any).personastate;
        token.picture = user.image;
      }
      return token;
    },
  },
};

// App Router兼容的NextAuth处理函数
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

额外操作步骤

  1. 移除旧的不兼容依赖:
    npm uninstall next-auth-steam
    
  2. 确保环境变量NEXTAUTH_URL和STEAM_API_KEY在生产环境中正确配置
  3. 重新构建项目:
    npm run build
    

为什么这个方案有效

  1. 完全适配App Router的Request类型要求,避免了NextApiRequest的类型冲突
  2. 手动实现Steam的OpenID认证逻辑,不依赖第三方库的Pages Router兼容代码
  3. 保留了你原本的Session扩展和业务逻辑,功能与开发环境一致

内容的提问来源于stack exchange,提问作者Noxx1ous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 07:32:17