【问题标题】:React Native app logs out when jwt refresh token is not expired当 jwt 刷新令牌未过期时,React Native 应用程序注销
【发布时间】: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
                }
            })
            
        })
    })
}

【问题讨论】:

    标签: javascript node.js reactjs react-native jwt


    【解决方案1】:

    更新 该错误是由于同时调用多个 API 造成的,并且所有人都请求了新的访问令牌和旧的刷新令牌。我使用link 中的代码解决了这个问题。

    【讨论】:

      猜你喜欢
      • 2017-11-09
      • 2021-08-22
      • 1970-01-01
      • 2018-07-30
      • 2020-02-20
      • 2017-07-08
      • 2015-12-13
      • 2019-07-04
      • 1970-01-01
      相关资源
      最近更新 更多