当 jwt 刷新令牌未过期时,React Native 应用程序注销
Posted
技术标签:
【中文标题】当 jwt 刷新令牌未过期时,React Native 应用程序注销【英文标题】:React Native app logs out when jwt refresh token is not expired 【发布时间】:2021-09-14 05:41:57 【问题描述】:我正在使用 JWT 令牌来验证我的 API 请求。访问令牌在 1 分钟后过期,刷新令牌在 1 年内过期。访问令牌过期后,会发送一个带有刷新令牌的 API 请求以获取一组新令牌。仅当刷新令牌有效且存在于数据库中时才会发送一组新令牌。我正在使用 Axios 拦截器来实现这一点。一段时间以来,一切似乎都可以正常工作。但是,即使刷新令牌有效并且数据库中确实存在,它也会将我注销。我假设我在 Axios 拦截器中遗漏了一些东西,或者与异步函数有关。
服务器端verifyRefreshToken函数中的错误日志“代码不匹配”,客户端updateToken函数中的“此处错误”。
客户端代码 API.js
// Response interceptor for API calls
API.interceptors.response.use((response) =>
return response
, async (error) =>
// reject promise if network error
if (!error.response)
console.log("Network Error");
return Promise.reject(error);
const originalRequest = error.config;
console.log(store.getState().auth)
// if access token is expired
if (error.response.status === 403 && error.response.data.message == "token expired")
// var refreshToken = await getRefreshToken() // get refresh token from local storage
var refreshToken = await store.getState().auth.refreshToken
// restore tokens using refresh token
await store.dispatch(await updateToken(refreshToken)) // get new set of tokens from server and store tokens in redux state
// var newAccessToken = await getToken() // get token from local storage
var newAccessToken = await store.getState().auth.accessToken
if(newAccessToken != null)
originalRequest.headers["Authorization"] = `Bearer $newAccessToken`;
return API(originalRequest)
return Promise.reject(error);
// if refresh token is expired or does not match
if (error.response.status === 403 && error.response.data.message == "false token")
socketDisconnect() // disconnect socket connection
signOut() // remove tokens from local storage
store.dispatch(logOut()) // set tokens in redux as null
return Promise.reject(error);
return Promise.reject(error);
);
更新令牌函数
export const updateToken = (rt) =>
return async (dispatch) =>
const data = await API.post('/auth/refreshToken',
token: rt
)
.then(async res =>
var accessToken = res.data.accessToken
var refreshToken = res.data.refreshToken
await storeToken(accessToken) // store access token in local storage
await storeRefreshToken(refreshToken) // store refresh token in local storage
dispatch(restoreToken(accessToken, refreshToken)) // store token in redux state
)
.catch(err =>
console.log("err here" + err) // LOG SHOWS ERROR HERE
)
服务器端代码 // /auth/refreshToken
// POST: /api/auth/refreshToken
router.post('/', (req, res) =>
var token = req.body
if(!token) res.status(403).send("status":false, "message": "false token", "result": "")
verifyRefreshToken(token)
.then(async data =>
var userName = data.userName
// get new tokens
var accessToken = await getAccessToken(userName)
var refreshToken = await getRefreshToken(userName)
res.json("status":true, "message": "token verified", "accessToken": accessToken, "refreshToken": refreshToken)
)
.catch(err =>
console.log(err);
res.status(403).send("status":false, "message": "false token", "result": "")
)
);
生成新的刷新令牌
// generate refresh token
const getRefreshToken = (userName) =>
return new Promise((resolve, reject) =>
var secret = process.env.REFRESH_TOKEN_SECRET
var options = expiresIn: '1y'
jwt.sign(userName,secret , options, (err, token) =>
if(err) reject("error")
var data = "userName": userName, "token": token
// delete all expired token from database
dbQueries.deleteRefreshToken(data, result =>
)
// add refresh token to database
dbQueries.addRefreshToken(data, result =>
if(result == "success")
console.log("added token " + token);
resolve(token)
else
reject("failure")
)
);
)
验证刷新令牌
// verify access token
const verifyRefreshToken = (token) =>
return new Promise((resolve, reject) =>
var secret = process.env.REFRESH_TOKEN_SECRET
if(!token) return reject("no token")
jwt.verify(token, secret, (err, user) =>
if(err)
return reject(err)
// check if the verified token and token from database matches
var data = "userName": user.userName
dbQueries.getRefreshToken(data, result =>
if(result.length == 0)
return reject("no data")
if(token === result[0].token)
resolve(user)
else
reject("code does not match") // LOGS THIS ERROR
)
)
)
【问题讨论】:
【参考方案1】:更新 该错误是由于同时调用多个 API 造成的,并且所有人都请求了新的访问令牌和旧的刷新令牌。我使用link 中的代码解决了这个问题。
【讨论】:
以上是关于当 jwt 刷新令牌未过期时,React Native 应用程序注销的主要内容,如果未能解决你的问题,请参考以下文章