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

Next.js中基于Referrer与User Agent生成并全局使用X-CSRF Token方案咨询

Next.js对接PHP API的CSRF认证解决方案

1. 生成CSRF并实现全局可用

第一步:编写统一的CSRF生成函数

确保客户端与PHP后端的MD5生成逻辑完全一致,兼容服务端(Node.js)和客户端环境:

// utils/csrf.ts
import crypto from 'crypto';
import CryptoJS from 'crypto-js';

// 与PHP后端匹配的CSRF生成逻辑:Referrer + User Agent + 机密字符串 → MD5
export function generateCSRF(referrer: string, userAgent: string, secret: string): string {
  const input = `${referrer}|${userAgent}|${secret}`;
  // 服务端用Node原生crypto,客户端用CryptoJS
  if (typeof window === 'undefined') {
    return crypto.createHash('md5').update(input).digest('hex');
  } else {
    return CryptoJS.MD5(input).toString();
  }
}

第二步:全局API请求封装

封装请求工具,自动生成并携带CSRF头,避免重复编写逻辑:

// utils/api.ts
import { generateCSRF } from './csrf';

// 从环境变量读取机密字符串(客户端需用NEXT_PUBLIC_前缀暴露)
const API_CSRF_SECRET = process.env.NEXT_PUBLIC_API_CSRF_SECRET!;

export async function fetchAPI(url: string, options: RequestInit = {}) {
  let referrer = '';
  let userAgent = '';

  if (typeof window !== 'undefined') {
    // 客户端获取Referrer,无值时回退到当前域名
    referrer = document.referrer || window.location.origin;
    userAgent = navigator.userAgent;
  }

  const csrf = generateCSRF(referrer, userAgent, API_CSRF_SECRET);
  const headers = {
    ...options.headers,
    'X-CSRF': csrf,
    'X-Referrer': referrer,
    'User-Agent': userAgent
  };

  return fetch(url, { ...options, headers });
}

可选:React Context全局注入

若组件需直接调用CSRF值,可通过Context全局注入:

// contexts/CSRFContext.tsx
import { createContext, useContext, useEffect, useState } from 'react';
import { generateCSRF } from '../utils/csrf';

const CSRFContext = createContext<string | null>(null);

export function CSRFProvider({ children }: { children: React.ReactNode }) {
  const [csrf, setCsrf] = useState<string | null>(null);
  const secret = process.env.NEXT_PUBLIC_API_CSRF_SECRET;

  useEffect(() => {
    if (typeof window !== 'undefined' && secret) {
      const referrer = document.referrer || window.location.origin;
      const userAgent = navigator.userAgent;
      setCsrf(generateCSRF(referrer, userAgent, secret));
    }
  }, []);

  return <CSRFContext.Provider value={csrf}>{children}</CSRFContext.Provider>;
}

export const useCSRF = () => useContext(CSRFContext);

在_app.tsx中包裹全局组件:

// pages/_app.tsx
import { CSRFProvider } from '../contexts/CSRFContext';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <CSRFProvider>
      <Component {...pageProps} />
    </CSRFProvider>
  );
}

2. 在getServerSideProps中获取Referrer与User Agent

getServerSideProps运行在服务端,需从请求对象中读取头信息:

// pages/[page].tsx
import { generateCSRF } from '../utils/csrf';
import fetch from 'node-fetch';
import type { GetServerSidePropsContext } from 'next';

export async function getServerSideProps(context: GetServerSidePropsContext) {
  const { req } = context;
  // HTTP头中Referrer拼写为referer,无值时回退到应用域名
  const referrer = req.headers.referer || process.env.NEXT_PUBLIC_APP_URL!;
  const userAgent = req.headers['user-agent'] || '';
  // 服务端机密字符串无需暴露给客户端,用普通环境变量
  const secret = process.env.API_CSRF_SECRET!;

  const csrf = generateCSRF(referrer, userAgent, secret);

  // 调用PHP API并携带认证头
  const res = await fetch(`${process.env.API_ENDPOINT}/your-path`, {
    headers: {
      'X-CSRF': csrf,
      'X-Referrer': referrer,
      'User-Agent': userAgent
    }
  });

  const data = await res.json();
  return { props: { data } };
}

关键注意事项

  • 确保PHP后端与客户端的机密字符串完全一致,客户端需用NEXT_PUBLIC_前缀暴露该变量。
  • HTTP头中Referrer的标准拼写是referer,不要写成referrer。
  • 处理头信息为空的场景,设置合理的回退值(如应用自身域名)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 09:50:30