Я пытаюсь отправить простой GET-запрос в конечную точку авторизации на внутреннем сервере, чтобы проверить токен пользователя jwt, который хранится в localStorage после успешной аутентификации (входа в систему). Я установил вспомогательную функцию (см. Ниже), которая будет отправлять запрос GET на сервер с токеном jwt в заголовке. Если получено состояние 200, я возвращаю значение true (авторизовано).
Эта вспомогательная функция вызывается в моем PrivateRoute HOC, и если true, то возвращает частный компонент, а если false, будет перенаправлять в Login.
По сути, я могу заставить работать защищенные маршруты, если просто декодирую токен и проверяю, существует ли токен, и, следовательно, пользователь вошел в систему. Однако это не проверка токена на сервере jwt verify и, следовательно, небезопасный. Я не уверен, нужно ли мне где-нибудь реализовывать асинхронный код? Я знаю, что шаг проверки должен существовать во внутреннем интерфейсе, и внешний интерфейс должен просто отправить запрос API с токеном в заголовке, но я не могу получить эту работу с частными маршрутами.
Я также попытался запустить вспомогательную функцию на главном компоненте приложения в качестве ловушки useEffect и обновить переменную состояния «loggedIn» в зависимости от того, возвращает ли вспомогательная функция авторизованный или нет, который затем может быть передан в качестве подпорки другим компонентам. , Я сделал это для того, чтобы компонент Nav Bar отображал «SIGN IN / REGISTER» или «SIGN OUT» в зависимости от того, является ли состояние «loggedIn» истинным или ложным.
Функция проверки токена на стороне сервера:
const jwt = require('jsonwebtoken');
module.exports = function (req, res, next) {
const token = req.header('auth-token');
if(!token) return res.status(401).send('Access Denied');
try {
const decoded = jwt.verify(token, process.env.TOKEN_SECRET);
req.user = decoded;
next();
} catch (err) {
res.status(400).send('Invalid Token');
}
}
Вспомогательная функция:
import React from 'react';
import { Redirect } from 'react-router-dom';
import axios from 'axios';
const checkAuth = {
isAuthorised: false,
userID: void (0),
authorise: function () {
const token = window.localStorage.getItem("access_token");
if (!token) {
console.log('Invalid Token');
window.localStorage.setItem("access_token", null);
}
const response = axios({
method: 'get',
url: 'http://localhost:3001/api/verify',
headers: { 'auth-token': token }
})
const data = response.data;
if (response.status === 200) {
this.isAuthorised = true;
this.userID = data._id;
return this.isAuthorised;
}
return this.isAuthorised;
},
logout: function () {
window.localStorage.setItem("access_token", null);
this.isAuthorised = false;
return <Redirect to="/" />
},
}
export default checkAuth;
Частный маршрут HOC:
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
import checkAuth from './helper';
const PrivateRoute = ({ component: Component, path, ...rest }) => {
return (
<Route
path={path}
{...rest}
render={props =>
checkAuth.authorise()
? <Component {...props} />
: <Redirect to={{ pathname: "/login" }} />
}
/>
);
}
export default PrivateRoute;
Компонент приложения (скрытие импорта):
const App = () => {
const [loggedIn, setLoggedIn] = useState(false);
const [user, setUser] = useState();
const verify = () => {
if (checkAuth.authorise()) {
setLoggedIn(true);
setUser(checkAuth.userID);
console.log('logged in');
return true;
} else {
console.log('not logged in');
return false;
}
}
useEffect(() => {
verify()
}, [loggedIn]);
return (
<div>
<NavBar loggedIn={loggedIn} user={user} />
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/story" component={Story} />
<Route path="/prologue" component={Prologue} />
<PrivateRoute path="/chapters" component={Chapters} />
<PrivateRoute path="/forum" component={Forum} />
<PrivateRoute path="/characters" component={Characters} />
<PrivateRoute path="/characters/:id" component={CharacterSheet} />
<Route path="/login" component={Login} />
<Route path="/register" component={Register} />
<Route component={NoMatch} />
</Switch>
</Router>
</div>
);
}
export default App;
Компонент NavBar (только соответствующая часть):
const NavBar = ({ loggedIn, user }) => {
return (
...
{loggedIn ? (
<Nav>
<h1 style={{ paddingRight: '30px', color: 'black', fontSize: '32pt'}}>Welcome, {user}</h1>
<Nav.Link href="/" onClick={() => checkAuth.logout()}>Sign Out</Nav.Link>
</Nav>
) : (
<Nav>
<Nav.Link href="/login">Login</Nav.Link>
<Nav.Link href="/register">Register</Nav.Link>
</Nav>
)}
...
)
}
export default NavBar;
Я ожидаю, что когда пользователь войдет в систему, NavBar будет обновляться, чтобы показать, что пользователь вошел в систему на основании функции помощника авторизации, вызываемой в результате ловушки useEffect.
Я бы также ожидал, что когда пользователь перенаправит на один из защищенных маршрутов (PrivateRoute), вспомогательная функция запустится и вернет true (после входа в систему), а затем отобразит.
Я получаю ожидаемые результаты, когда вместо вызова API в вспомогательной функции используется следующий код (однако, как я понимаю, это НЕ правильная авторизация):
authorise: function () {
const token = window.localStorage.getItem("access_token");
if (!token) {
console.log('Invalid Token');
window.localStorage.setItem("access_token", "");
}
try {
const decoded = decode(token);
console.log(decoded)
if (decoded) {
this.isAuthorised = true;
this.userID = decoded._id;
return this.isAuthorised;
}
}
catch {
console.log('invalid token')
}
return this.isAuthorised;
},
На данный момент вход в систему, похоже, ничего не делает - хотя маркер пользователя получен и сохранен в LocalStorage.