即使使用“Access-Control-Allow-Origin”标头,NextJS 端点也会出现 CORS 错误

问题描述 投票:0回答:2

我有一个 React 前端调用 NextJS 端点。我相信使用

next.config.js
文件在服务器上设置了正确的标头...

module.exports = {
    reactStrictMode: true,
    webpack: (config, options) => {
        if (!options.isServer) {
            config.resolve.fallback.fs = false
        }

        return config
    },
    async headers() {
        return [
            {
                source: '/api/:path*',
                headers: [
                    { key: 'origins', value: '*' },
                    { key: 'Bypass-Tunnel-Reminder', value: '*' },
                    { key: 'Access-Control-Allow-Origin', value: '*' },
                    { key: 'Access-Control-Request-Methods', value: 'POST, GET, OPTIONS' },
                    { key: 'Access-Control-Allow-Headers', value: 'Authorization, Content-Type' },
                ],
            },
        ]
    },
}

尽管如此,当我从前端调用端点时,我不断收到 CORS 错误。Access to XMLHttpRequest at 'http://localhost:3001/api/github/setCredentials' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

这是前端代码...

axios.post(
                    'http://localhost:3001/github/setCredentials',
                    {
                        accessCode,
                    },
                    {
                        headers: {
                            Authorization: localStorage.getItem('jwt_token'),
                            'Content-Type': 'application/x-www-form-urlencoded',
                        },
                    },
                )

jwt_token
看起来像“承载者

端点看起来像这样...

const authenticate = (method, req, res) =>
    new Promise((resolve, reject) => {
        passport.authenticate(method, { session: false }, (error, token) => {
            if (error) {
                reject(error)
            } else {
                resolve(token)
            }
        })(req, res)
    })

passport.use(jwtStrategy)

const handler = nextConnect({
    onError: (err, req: NextApiRequest, res: NextApiResponse, next) => {
        console.error(err.stack)
        res.status(500).end('Something broke!')
    },
    onNoMatch: (req: NextApiRequest, res: NextApiResponse) => {
        res.status(404).end('Page is not found')
    },
})
    .use(passport.initialize())
    .post(async (req: NextApiRequest, res: NextApiResponse) => {
        try {
            const user = await authenticate('jwt', req, res)
            if (!user) return res.status(403).json({ error: 'Unauthenticated user' })
            
            return res.status(200).json({ success: true })
        } catch (err) {
            return res.status(500).json({ error: err.toString() })
        }
    })

export default handler

passport.js 身份验证策略如下所示...

const opts: any = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken()
opts.secretOrKey = JWT_SECRET

export const jwtStrategy = new JwtStrategy(opts, function (jwt_payload, done) {
    mongoose
        .getUserByEthAddress(jwt_payload.address)
        .then((user: User | null) => {
            return done(null, user)
        })
        .catch((err) => {
            return done(err, false)
        })
})

有趣的是(令人沮丧?),击中我的其他端点不会导致 CORS 错误。另外,当我从请求中删除“Authorization”标头时,我收到中间件抛出的典型 403 错误,无法找到用户,但没有 CORS 错误。

此外,当我使用授权令牌和所有内容在 Postman 上进行此调用时,它运行良好,因此身份验证层不是问题。

有什么想法可能导致这种情况吗?我读到的所有内容似乎都在

next.config.js
文件中设置“Access-Control...”标头可以解决此问题,但事实并非如此。谢谢!

api next.js cors authorization
2个回答
1
投票

@jub0bs 引导我解决了这个问题。我需要做几件事。

  1. 像这样设置 nextjs-cors 中间件...
    .use(async (req: NextApiRequest, res: NextApiResponse, next) => {
        await NextCors(req, res, {
            // Options
            methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
            origin: '*',
            optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
        })
        next()
    })
  1. 向处理程序添加 OPTIONS 方法...
    .options((req: NextApiRequest, res: NextApiResponse) => {
        return res.status(200).send('ok')
    })

然后,我的护照中间件使用一个

req.user
对象填充请求,我可以在处理 POST 方法时使用该对象。


0
投票

我将 next.js 中间件配置为处理接受的来源,并仅在生产模式接受来源类型时返回网站或路由。对于本地开发,我将原始值设置为

*
,因为不需要为本地主机处理 CORS。您可以将此代码复制粘贴到您的
middleware.ts
文件中。

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const isProduction = process.env.DATASET === 'production';
const corsOrigins = isProduction
    ? [
          'domain1',
          'domain2',
          'domain3',
          'domain4',
      ]
    : ['*'];

export function middleware(req: NextRequest) {
    const origin = req.headers.get('origin');
    const res = NextResponse.next();

    // Set CORS headers
    res.headers.set('Access-Control-Allow-Credentials', 'true');
    res.headers.set('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT');
    res.headers.set(
        'Access-Control-Allow-Headers',
        'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
    );

    if (corsOrigins.includes('*') || corsOrigins.includes(origin || '')) {
        res.headers.set('Access-Control-Allow-Origin', origin || '*');
    }

    return res;
}

export const config = {
    matcher: '/api/:path*', // Match all API routes
};

请修改

corsOrigins
数组值(添加所有您需要的域)。

© www.soinside.com 2019 - 2024. All rights reserved.