#reactjs #mongodb #authentication #jwt
Вопрос:
Я создаю приложение React с аутентификацией с использованием JWTs. Я могу создать нового пользователя. Я могу войти в систему этого пользователя. Но я не могу обновить информацию об этом пользователе в MongoDB, к которому он подключен. Ошибка, которую я получаю, заключается в следующем:
'Unable to verify token'
На передней панели информационная страница пользователя, которую они редактируют, выглядит следующим образом:
UserInfoPage.js
import { useState, useEffect } from 'react'; import { useHistory } from 'react-router-dom'; import axios from 'axios'; import { useToken } from '../auth/useToken'; import { useUser } from '../auth/useUser'; export const UserInfoPage = () =gt; { const user = useUser(); const [token,setToken] = useToken(); const {id, email, info } = user; // We'll use the history to navigate the user // programmatically later on (we're not using it yet) const history = useHistory(); // These states are bound to the values of the text inputs // on the page (see JSX below). const [favoriteFood, setFavoriteFood] = useState(info.favoriteFood || ''); const [hairColor, setHairColor] = useState(info.hairColor || ''); const [bio, setBio] = useState(info.bio || ''); // These state variables control whether or not we show // the success and error message sections after making // a network request (see JSX below). const [showSuccessMessage, setShowSuccessMessage] = useState(false); const [showErrorMessage, setShowErrorMessage] = useState(false); // This useEffect hook automatically hides the // success and error messages after 3 seconds when they're shown. // Just a little user interface improvement. useEffect(() =gt; { if (showSuccessMessage || showErrorMessage) { setTimeout(() =gt; { setShowSuccessMessage(false); setShowErrorMessage(false); }, 3000); } }, [showSuccessMessage, showErrorMessage]); const saveChanges = async () =gt; { // Send a request to the server to // update the user's info with any changes we've // made to the text input values //alert('Save functionality not implemented yet'); try{ const response = await axios.put(`/api/users/${id}`, { favoriteFood, hairColor, bio, }, { headers: { Authorization: `Bearer ${token}`} }); const { token: newToken } = response.data; setToken(newToken); setShowSuccessMessage(true); }catch(error){ setShowErrorMessage(true); console.log(error); } } const logOut = () =gt; { // We'll want to log the user out here // and send them to the "login page" alert('Log out functionality not implemented yet'); } const resetValues = () =gt; { // Reset the text input values to // their starting values (the data we loaded from the server) //alert('Reset functionality not implemented yet'); setFavoriteFood(info.favoriteFood); setHairColor(info.hairColor); setBio(info.bio); } // And here we have the JSX for our component. It's pretty straightforward return ( lt;div className="content-container"gt; lt;h1gt;Info for {email}lt;/h1gt; {showSuccessMessage amp;amp; lt;div className="success"gt;Successfully saved user data!lt;/divgt;} {showErrorMessage amp;amp; lt;div className="fail"gt;Uh oh... something went wrong and we couldn't save changeslt;/divgt;} lt;labelgt; Favorite Food: lt;input onChange={e =gt; setFavoriteFood(e.target.value)} value={favoriteFood} /gt; lt;/labelgt; lt;labelgt; Hair Color: lt;input onChange={e =gt; setHairColor(e.target.value)} value={hairColor} /gt; lt;/labelgt; lt;labelgt; Bio: lt;input onChange={e =gt; setBio(e.target.value)} value={bio} /gt; lt;/labelgt; lt;hr /gt; lt;button onClick={saveChanges}gt;Save Changeslt;/buttongt; lt;button onClick={resetValues}gt;Reset Valueslt;/buttongt; lt;button onClick={logOut}gt;Log Outlt;/buttongt; lt;/divgt; ); }
Внутренний маршрут, по которому отправляется запрос:
updateUserInfoRoute.js
import jwt from 'jsonwebtoken'; import { ObjectID } from 'mongodb'; import { getDbConnection } from '../db'; export const updateUserInfoRoute = { path: '/api/users/:userId', method: 'put', handler: async (req, res) =gt; { try{ const{ authorization } = req.headers; const {userId} = req.params; const updates = ( ({ favoriteFood, hairColor, bio, }) =gt; ({ favoriteFood, hairColor, bio, }))(req.body); if (!authorization){ return res.status(401).json({message: 'No authorization headers sent'}); } const token = authorization.split('')[1]; jwt.verify(token, process.env.JWT_SECRET, async (err, decoded ) =gt; { if (err) return res.status(401).json({message: 'Unable to verify token'}); console.log(err); const { id } = decoded; if (id !== userId) return res.status(403).json({message: 'No authorization to update user data' }); const db = getDbConnection('react-auth-db'); const result = await db.collection('users').findOneAndUpdate( { _id: ObjectID(id) }, { $set: { info: updates }}, { returnOriginal: false}, ); const {email, isVerified, info } = result.value; jwt.sign({ id, email, isVerified, info }, process.env.JWT_SECRET, {expiresIn: '365d'}, (err, token) =gt;{ if(err){ return res.status(200).json(err); } res.status(200).json({ token }); }) }) }catch(error){ console.log("Mazzo the error is: " error); } }, }
В чем здесь проблема? Спасибо тебе, Железный человек
Ответ №1:
Вы передаете токен с интерфейса на сервер в этом формате,
Bearer token
Но на маршруте обновления.код js, вы разделяете токен без пробела,
const token = authorization.split('')[1];
Для этого кода вывод токена будет
e
Чтобы решить эту проблему, просто добавьте место в методе разделения,
const token = authorization.split(' ')[1];
Комментарии:
1. Вы попали в точку. Большое спасибо, парень. Я отмечу ваш ответ как решение. Выпей хорошего.