【问题标题】:Request fails after retrieving JWT token检索 JWT 令牌后请求失败
【发布时间】:2019-06-26 23:43:30
【问题描述】:

我正在使用带有 DRF 的 Django JWT 和带有 axios 的 Vue Js。当用户登录时,我检索令牌并将其存储在我已验证可以工作的本地存储中。然后我重定向到一个新页面,在那里我发出另一个请求以获取数据。每次我重定向到这个页面时,我都会得到一个 401 未授权,当我刷新页面时它工作正常。在发出第二个请求之前,我检查以确保令牌已存储。我试图在创建的钩子中获取重定向页面上的数据。我还创建了一个 axios 实例来处理标头并使用基本路由,然后将其导入到需要的文件中,我不确定这是否与它有关。这也仅在令牌过期并且您尝试检索新令牌时发生。我应该刷新令牌而不是尝试获取新令牌吗?

Axios 实例

import axios from 'axios'

export default axios.create({
  baseURL: `http://127.0.0.1:8000/`,
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'JWT ' + localStorage.getItem('token')
  },
  xsrfCookieName: 'csrftoken',
  xsrfHeaderName: 'X-CSRFToken',
  withCredentials: true
})

编辑

api.js

import axios from 'axios'

export default axios.create({
  baseURL: `http://127.0.0.1:8000/`,
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'JWT ' + localStorage.getItem('token')
  },
  xsrfCookieName: 'csrftoken',
  xsrfHeaderName: 'X-CSRFToken',
  withCredentials: true
})

AppLogin.vue

点击登录按钮触发确认

 confirm: function() {
       API.post("accounts/login/", {
        email: this.email,
        password: this.password,
       })
        .then(result => {
          console.log(result.data.token);
          this.token = result.data.token;
          localStorage.setItem("token", this.token);
          this.getUserInfo()
        })
        .catch(error => {
          console.log(error);
        });

    },
    getUserInfo: function(){
      axios.get("http://127.0.0.1:8000/userinfo/get/", {
        headers: {
          'Content-Type': 'application/json',
          Authorization: 'JWT ' + this.token
        }
      })
        .then(response => {
          console.log(response.data.pos);
          var pos = response.data.pos;
          this.reroute(pos);
        })
        .catch(error => {
          console.log(error);
        });
    },
    reroute(pos) {
      if (pos == "owner") {
        this.$router.push({ path: "/bizhome" });
      } else {
        this.$router.push({ path: "/" });
      }
    }

BizHome.vue

这是登录成功后重定向到的页面

created: function() {
    this.getLocations();
  },
  methods: {
    getLocations() {
      API.get("business/")
        .then(response => {
          this.biz = response.data;
        })
        .catch(error => {
          console.log(error);
        });

      API.get("locations/")
        .then(response => {
          this.bizLocations = response.data;
        })
        .catch(error => {
          console.log(error);
        });
    },
  }

解决方案

使用我从下面的 YuuwakU 获得的一些建议,我将标头直接添加到 getLocations 方法中的 get 调用中,以覆盖 axios 实例标头。似乎在实例中更新令牌之前加载的新页面。但是,此解决方案的一个缺点是我现在必须将标头直接添加到我进行的所有调用中。实例中的标头永远不会更新。我确实将API.defaults.headers.common['Authorization'] = 'JWT ' + result.data.token; 添加到了成功检索令牌的confirm 方法中,该令牌应该已经更新了实例的令牌。这对我不起作用,如果有人有任何想法,我有兴趣听听他们的意见

编辑 2

我确实弄清楚了为什么 axios 实例没有更新它,因为我试图从 api.js 中的本地存储中获取令牌并且它覆盖了它。现在它可以工作了,但令牌不是持久的,所以这也不理想。如果我找到更好的解决方案,我会更新。

最终更新

我终于想出了一个好的解决方案。我从 api.js 中的 axios 实例中删除了授权标头,然后从所有 axios 调用中删除了所有标头。在成功登录的确认方法中,我添加了前面提到的这一行API.defaults.headers.common['Authorization'] = 'JWT ' + result.data.token;,并将令牌添加到本地存储。我有一个在页面加载之前运行的验证令牌方法。在我发出发布请求以验证我添加的令牌之前的那个方法 API.defaults.headers.common['Authorization'] = 'JWT ' + localstorage.getItem('token'); 。这允许用户离开站点并返回并在有效的情况下仍然使用令牌,并且不需要在每次调用时设置标头。

【问题讨论】:

    标签: django-rest-framework jwt axios


    【解决方案1】:

    发生这种情况的原因是,已经使用 localStorage 中存在的过期令牌创建了 axios 实例。因此,您必须确保在登录后使用新获取的令牌更新 axios 实例,否则您最终将使用旧令牌,直到重新加载新页面。请尝试以下操作:

    import axios from 'axios'
    
    export default axios.create({
      baseURL: `http://127.0.0.1:8000/`,
      headers: {
        'Content-Type': 'application/json',
        Authorization() { // Converted to a method, similar concept to a vue data property
          return `JWT  ${localStorage.getItem('token')}`,
        }
      },
      xsrfCookieName: 'csrftoken',
      xsrfHeaderName: 'X-CSRFToken',
      withCredentials: true
    })
    
    

    或者,您甚至可以使用 axios 拦截器从 localStorage 中获取每个请求:

    // Add a request interceptor
    axios.interceptors.request.use(config => {
        // Do something before request is sent
        config.headers = {
          'Content-Type': 'application/json',
          Authorization: 'JWT ' + localStorage.getItem('token')
        }
        return config
      }, function (error) {
        // Do something with request error
        return Promise.reject(error);
      });
    
    

    【讨论】:

    • 我很欣赏这个答案,但这并不能真正解决我的问题。检查用户是否登录没有问题。发生的情况是,如果令牌过期并且用户再次登录,页面将重定向到主页并且随后的 ajax 请求失败但刷新主页并再次尝试请求。
    • 嘿@Taylor,对于这个问题的误解,我已经更新了我的答案。
    • 我也认为问题在于实例没有刷新,但我尝试了您的两种解决方案,但不幸的是它们都没有工作。奇怪的是,我有一个验证功能,可以在页面加载时检查令牌。我从使用相同 axios 实例的 utils 函数中导入它。我在 beforeCreate 钩子中调用 verify 函数,在 created 钩子中调用 get 。验证功能有效,但调用无效
    • 谢谢,我很感激。我在上面的编辑中添加代码
    • 很多时候,当您为数据道具设置值时,它会失去反应性。所以,不要依赖this.token。在confirm方法中直接localStorage.setItem("token", response.data.token);,然后在getUserInfo中使用Authorization: 'JWT ' + localStorage.getItem('token')
    猜你喜欢
    • 1970-01-01
    • 2020-02-21
    • 2017-06-23
    • 1970-01-01
    • 2019-05-23
    • 2019-11-21
    • 2013-05-02
    • 2013-10-22
    • 1970-01-01
    相关资源
    最近更新 更多