另一个noob问题。我使用JWT授权将我的用户登录到系统,获取令牌并将其保存在localstorage
中,然后发送保存数据的帖子请求(基本上是一个大表格)。问题是,服务器在给定时间(大约20分钟)之后使令牌无效,因此,我的一些帖子请求正在返回401 status
。如何在发送帖子请求之前验证(如果需要,显示登录提示)?我使用redux-form
制作表单。
这是我的身份验证:
export function loginUser(creds) {
const data = querystring.stringify({_username: creds.username, _password: creds.password});
let config = {
method: 'POST',
headers: { 'Content-Type':'application/x-www-form-urlencoded' },
body: data
};
return dispatch => {
// We dispatch requestLogin to kickoff the call to the API
dispatch(requestLogin(creds));
return fetch(BASE_URL+'/login_check', config)
.then(response =>
response.json().then(user => ({ user, response }))
).then(({ user, response }) => {
if (!response.ok) {
// If there was a problem, we want to
// dispatch the error condition
dispatch(loginError(user.message));
return Promise.reject(user)
} else {
// If login was successful, set the token in local storage
localStorage.setItem('id_token', user.token);
let token = localStorage.getItem('id_token')
console.log(token);
// Dispatch the success action
dispatch(receiveLogin(user));
}
}).catch(err => console.log("Error: ", err))
}
}
以及POST
请求(我从values
获取redux-form
个对象)
const token = localStorage.getItem('id_token');
const AuthStr = 'Bearer '.concat(token);
let headers ={
headers: { 'Content-Type':'application/json','Authorization' : AuthStr }
};
export default (async function showResults(values, dispatch) {
axios.post(BASE_URL + '/new', values, headers)
.then(function (response) {
console.log(values);
console.log(response);
})
.catch(function (error) {
console.log(token);
console.log(values)
console.log(error.response);
});
});
P.P.S:如果有人提出改进我的代码的建议,请随时发表评论。
答案 0 :(得分:8)
可以通过两种方式检查JWT到期时间。首先,您必须安装jsonwebtoken包并在文件顶部需要它。此后,您可以按照以下方式检查JWT到期,然后再发送任何休息请求。
选项1
var isExpired = false;
const token = localStorage.getItem('id_token');
var decodedToken=jwt.decode(token, {complete: true});
var dateNow = new Date();
if(decodedToken.exp < dateNow.getTime())
isExpired = true;
选项2
const token = localStorage.getItem('id_token');
jwt.verify(token, 'shhhhh', function(err, decoded) {
if (err) {
/*
err = {
name: 'TokenExpiredError',
message: 'jwt expired',
expiredAt: 1408621000
}
*/
}
});
检查该方法的错误。如果是TokenExpiredError则表示令牌已过期。
答案 1 :(得分:1)
您还可以使用MiddleWare检查令牌是否已过期。如果令牌即将过期,您甚至可以更新令牌。例如,您可以执行以下所示的操作;
export function jwtMiddleware({ dispatch, getState }) {
return (next) => (action) => {
switch (action.type) {
case 'CHECK_AUTH_TOKEN' :
if (getState().auth && getState().auth.token) {
var tokenExpiration = jwtDecode(getState().auth.token).exp;
var tokenExpirationTimeInSeconds = (tokenExpiration - moment(Math.floor(Date.now() / 1000)));
if (tokenExpiration && tokenExpirationTimeInSeconds < 20) {
history.push(i18next.t('translation:routes.auth.logout'));
}
}
break;
case 'UPDATE_AUTH_TOKEN' :
if (getState().auth && getState().auth.token) {
var tokenExpiration = jwtDecode(getState().auth.token).exp;
var tokenExpirationTimeInSeconds = (tokenExpiration - moment(Math.floor(Date.now() / 1000)));
if (tokenExpiration && tokenExpirationTimeInSeconds < 100 && tokenExpirationTimeInSeconds > 20) {
if (!getState().auth.fetching) {
return dispatch(refreshAuthToken(getState().auth));
}
}
}
break;
case 'REFRESH_AUTH_TOKEN_FAIL' :
if (getState().auth && getState().auth.token) {
return dispatch(removeAuthToken(getState().auth)).then(response => {
history.push(i18next.t('translation:routes.auth.logout'));
});
}
break;
}
return next(action);
}
}
答案 2 :(得分:1)
这是jwt-decode库的一种解决方案,它通过将JWT令牌中的exp属性与当前时间进行比较。 (JWT令牌只是Base64编码的字符串)
安装jwt-decode(npm install jwt-decode --save
)
let token = localStorage.getItem(TOKEN);
let decodedToken = jwt_decode(token);
console.log("Decoded Token", decodedToken);
let currentDate = new Date();
// JWT exp is in seconds
if (decodedToken.exp * 1000 < currentDate.getTime()) {
console.log("Token expired.");
} else {
console.log("Valid token");
result = true;
}
重要提示:jwt-decode无法验证令牌,任何格式正确的JWT都可以解码。您应该使用express-jwt,koa-jwt,Owin Bearer JWT等在服务器端逻辑中验证令牌。