我正在尝试向后端的授权端点发送一个简单的GET请求,以验证成功验证(登录)后在localStorage中保存的用户jwt令牌。我已经设置了一个辅助函数(请参见下文),该函数将在标头中带有jwt令牌的情况下向服务器发出GET请求,如果接收到状态200,则返回true(已授权)。
此辅助函数在我的PrivateRoute HOC中调用,如果为true,则返回私有组件;如果为false,则重定向到Login。
基本上,如果我只是解码令牌并验证令牌是否存在,因此用户已经登录,我就可以使受保护的路由正常工作。但是,这并不是针对服务器jwt verify来检查令牌,因此并不安全。我不确定是否需要在任何地方实现异步代码?我知道验证步骤必须在后端执行,前端应该只发送标头中带有令牌的API请求,但我似乎无法通过私有路由来完成这项工作。
我还尝试过在主App组件上将helper函数作为useEffect挂钩运行,并根据helper函数是否返回授权来更新“ loggedIn”状态变量,然后可以将其作为道具传递给其他组件。我已经完成了此操作,以使导航栏组件根据“ loggedIn”状态是true还是false来显示“ SIGN IN / REGISTER”或“ SIGN OUT”。
服务器端验证令牌功能:
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)时,helper函数将运行并返回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中。
答案 0 :(得分:0)
axios返回一个承诺,因此,基本上,您需要将验证代码更改为以下内容:
return axios({
method: 'get',
url: 'http://localhost:3001/api/verify',
headers: { 'auth-token': token }
})
.then(response => {
const data = response.data;
if (response.status === 200) {
this.isAuthorised = true;
this.userID = data._id;
}
return this.isAuthorised;
});
然后将checkAuth.authorise()
呼叫也作为承诺进行处理