您问题的第一部分的答案是:与邮差的 CORS.
对于第二部分,我利用短期访问令牌的概念编写了一个非常小的代码(太简化了)。
// utils/protector.js
let oldToken, newToken;
const checkToken = ({ headers: { 'x-access-token': token } }) =>
token && (token === oldToken || token === newToken);
const refreshToken = () => {
oldToken = newToken;
newToken = Math.random().toString(36).substr(2);
setTimeout(refreshToken, 3 * 60 * 60 * 1000); // each token is valid for 3 hrs
};
refreshToken();
export { checkToken, newToken as accessToken };
// api/user.js
import { checkToken } from '../../utils/protector';
const handler = (req, res) => {
// just add this line to the top of your handler
if (!checkToken(req)) return res.status(403).send();
// your API logic here...
res.status(200).json({ name: 'John Doe' });
};
export default handler;
现在在页面中您想要使用受保护的 API:
// index.js
import { useState, useEffect } from 'react';
import { accessToken } from '../utils/protector';
const Home = ({ accessToken }) => {
const [user, setUser] = useState('Guest');
useEffect(() => {
// this will be called from the client
fetch('/api/user', { headers: { 'x-access-token': accessToken } })
.then((response) => response.json())
.then((data) => setUser(data.name));
return () => {};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return <div>Hello {user}!</div>;
};
const getServerSideProps = async () => {
return { props: { accessToken } };
};
export default Home;
export { getServerSideProps };
使用受保护路由的任何页面都应该在服务器端呈现,否则保护器代码将与客户端捆绑在一起并在浏览器中执行,从而导致服务器端(API)和客户端产生不同的令牌。
的概念oldToken
and newToken
可能看起来很不清楚。认为:
我假设用户在您的页面上执行调用受保护 API 的操作之前只需要不到 3 小时的时间。
超时设置为 3 小时,即使令牌的有效时间是其时间的两倍,因为如果超时为一半(即 1.5 小时)并且(上述)用户在 01:31 触发 API 调用。然后oldToken
is the newToken
, and newToken
较新,两者都与用户拥有的不匹配。
因此,为了保证收到的令牌至少在 3 小时内有效,总生存时间是两倍。令牌的有效期可能为 6 小时(例如对于 12:00 访问该网站的用户)。