我的JWT身份验证方法不允许进行Cloudinary上传

时间:2018-08-07 21:12:37

标签: node.js reactjs cors jwt cloudinary

我几乎完成了Brad Traversy的Udemy教程,名为“ MERN Stack Front To Back”,并且遇到了两个类似的错误,试图通过允许用户选择使用Cloudinary上传照片来扩展其应用。这两个错误都与CORS请求有关。

在进入该应用之前,了解此应用可能很重要,因为它使用npm Concurrently运行Node服务器,然后使用相同的npm run dev命令运行React / Redux客户端-并且不使用中间件处理CORS要求。所以我的第一个问题是,这种设置如何解决中间件的需求?在我看来,他们仍在运行单独的服务器...

无论Brad Traversy的应用为什么没有这种中间件,当我将自己的新操作添加到应用的着陆页时,该操作就以与其他组件相同的方式向api发送请求,例如:

componentDidMount() {
  this.props.getAllAlerts();
}

export function getAllAlerts() {
  const request = axios.get(`${ROOT_URL}/api/alert`);
  return {
    type: GET_ALL_ALERTS,
    payload: request
  };
}

我收到以下错误: “无法加载http://localhost:5000/api/alert:对预检请求的响应未通过访问控制检查:所请求的资源上没有'Access-Control-Allow-Origin'标头。因此,源'http://localhost:3000'不允许访问。”

我实际上完全通过添加npm cors中间件并在我的api服务器中使用它完全解决了该错误。

app.use(cors());

还是,我想知道为什么它首先在其他组件不需要api的情况下向api发出axios请求的原因-因为也许它将有助于理解为什么后来在什么时候遇到了非常类似的错误添加一个将照片从浏览器直接上传到Cloudinary的组件。这是动作:

export const uploadFile = event => {
  const file = event.target.files[0];
  const CLOUDINARY_URL = `https://api.cloudinary.com/v1_1/${myCloudinaryApi}/upload`;
  const CLOUDINARY_UPLOAD_PRESET = CLOUDINARY_UPLOAD_PRESET;
  const formData = new FormData();
  formData.append("file", file);
  formData.append("upload_preset", CLOUDINARY_UPLOAD_PRESET);
  return dispatch => {
    return axios({
      url: CLOUDINARY_URL,
      method: "POST",
      skipAuthorization: true,
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      data: formData
    })
      .then(response => {
        dispatch({
          type: UPLOAD_FILE,
          payload: response.data.secure_url
        });
      })
      .catch(function(err) {
        console.log(err);
      });
  };
};

这是错误: “无法加载https://api.cloudinary.com/v1_1/alertsapi/upload:请求标题字段在飞行前响应中不允许Access-Control-Allow-Headers进行授权。”

即使使用cors中间件,我也不明白为什么会得到这个。

最后,出现了一个看起来很相关的皱纹:该应用程序每次加载顶级组件时都会检查JWT令牌:

// Check for token
if (localStorage.jwtToken) {
  // Set auth token header auth
  setAuthToken(localStorage.jwtToken);
  // Decode token and get user info and exp
  const decoded = jwt_decode(localStorage.jwtToken);
  // Set user and isAuthenticated
  store.dispatch(setCurrentUser(decoded));

  // Check for expired token
  const currentTime = Date.now() / 1000;
  if (decoded.exp < currentTime) {
    // Logout user
    store.dispatch(logoutUser());
    // Clear current Profile
    store.dispatch(clearCurrentProfile());
    // Redirect to login
    window.location.href = "/login";
  }
}

class App extends Component {
  render() {
    return ( 
...

如果我取消此检查,则uploadFile操作可以正常工作。因此,如果没有其他方法可以解决问题,是否有办法仅针对Cloudinary上传内容绕过此检查?

在此先感谢任何人的帮助。让我知道是否可以提供有关该应用程序的任何其他信息,可能会有所帮助。

1 个答案:

答案 0 :(得分:0)

我想出了第二个问题的解决方案。原来, uploadFile 操作中的axios请求包括一个 Authorization 标头,该标头是在我的身份验证检查中通过功能-ne ''设置的。这就是导致上述第二个错误的原因。不幸的是,该功能是从另一个文件导入的,引起了我的注意。在这里:

'foo,bar;baz' -split '[,;]'

Cloudinary请求不允许此标头。要删除我添加的不需要的标题

'foo', 'bar', 'baz'

紧接在 uploadFile 操作中的setAuthToken(localStorage.jwtToken)行之后。这允许文件成功上载,但是这也意味着,如果另一个axios请求直接跟随此操作,则它将没有Authorization标头。在这种情况下,下一个动作的确包含了一个要求Authorization标头的axios请求,因此有必要在该操作之前手动将其添加回去:

const setAuthToken = (token`enter code here`) => { if (token) { // Apply to every request axios.defaults.headers.common["Authorization"] = token; } else { // Delete auth header delete axios.defaults.headers.common["Authorization"]; } };

第二个问题解决了。我仍然不清楚为什么将我自己的请求添加到相同的api会导致CORS错误。