1

logout当函数调用 using时,我试图将用户列入黑名单 django-rest-framework-simplejwt。我可以从页面注销,但在终端中不断收到 400 个错误请求。我相信令牌还没有被销毁,而且在我的 APIview 中我也得到了"detail": "Method \"GET\" not allowed."。你能看出我的错误吗?

[ 更新 ]

终端错误

Bad Request: /blacklist/
[21/Aug/2020 10:06:24] "POST /blacklist/ HTTP/1.1" 400 0

设置.py

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=14),
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,
    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,
    'AUTH_HEADER_TYPES': ('JWT',),
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',
    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',
}

视图.py

class LogoutAndBlacklistRefreshToken(APIView):
    permission_classes = (AllowAny,)
    authentication_classes = ()

    def post(self, request):
        try:
            refresh_token = request.data["refresh_token"]
            token = RefreshToken(refresh_token)
            token.blacklist()

            return Response(status=status.HTTP_205_RESET_CONTENT)
        except Exception as e:
            return Response(status=status.HTTP_400_BAD_REQUEST)

网址.py

urlpatterns = [
    path('', include(router.urls)),
    path('admin/', admin.site.urls),
    path(
        'blacklist/', LogoutAndBlacklistRefreshToken.as_view(),
        name="blacklist"
    ),
    path('api-auth/', include('rest_framework.urls')),
    path(
        'api-token/', TokenObtainPairView.as_view(),
        name='token-obtain'
    ),
    path(
        'api-token-refresh/', TokenRefreshView.as_view(),
        name='token-refresh'
   ),
    path(
        'api-token-verify', TokenVerifyView.as_view(), 
        name='token-verify'
    ),
]

axios-base.js

import axios from "axios";
import store from "../store/index";
// API URL
const ApiUrl = "http://localhost:8000";

const axiosBase = axios.create({
  baseURL: ApiUrl,
  headers: { ContentType: "application/json" },
});

const getAPI = axios.create({
  baseURL: ApiUrl,
});

getAPI.interceptors.response.use(undefined, function(err) {
  // if error response status is 401, it means the request was
  // invalid due to expired access token.
  if (err.config && err.response && err.response.status === 401) {
    // attempt to obtain new access token by running
    // 'refreshToken' action
    store
      .dispatch("refreshToken")
      .then((access) => {
        // if succesfull resend the request to get the data from server
        axios
          .request({
            baseURL: ApiUrl,
            method: "get",
            headers: { Authorization: `Bearer ${access}` },
            url: "/",
          })
          .then((response) => {
            // if successfully received the data store it in store.state.
            // APIData so that 'Downloads' component can grab the
            // data from it and display to the client.
            console.log("Success");
            store.state.APIData = response.data;
          })
          .catch((err) => {
            console.log("Got error while access token");
            return Promise.reject(err);
          });
      })
      .catch((err) => {
        return Promise.reject(err);
      });
  }
});

export { axiosBase, getAPI };

Vuex 商店

import Vue from "vue";
import Vuex from "vuex";
import { axiosBase } from "../api/axios-base";
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    accessToken: localStorage.getItem("access_token") || null, // makes sure the user is logged in even after
    // refreshing the page
    refreshToken: localStorage.getItem("refresh_token") || null,
    APIData: "", // received data from the backend API is stored here.
  },
  getters: {
    loggedIn(state) {
      return state.accessToken != null;
    },
  },
  mutations: {
    updateLocalStorage(state, { access, refresh }) {
      localStorage.setItem("access_token", access);
      localStorage.setItem("refresh_token", refresh);
      state.accessToken = access;
      state.refreshToken = refresh;
    },
    updateAccess(state, access) {
      state.accessToken = access;
    },
    destroyToken(state) {
      state.accessToken = null;
      state.refreshToken = null;
    },
  },
  actions: {
    // run the below action to get a new access token on expiration
    refreshToken(context) {
      return new Promise((resolve, reject) => {
        axiosBase
          .post("/api-token-refresh/", {
            refresh: context.state.refreshToken,
          }) // send the stored refresh token to the backend API
          .then((response) => {
            // if API sends back new access and refresh token update the store
            console.log("New access successfully generated");
            context.commit("updateAccess", response.data.access);
            resolve(response.data.access);
          })
          .catch((err) => {
            console.log("error in refreshToken Task");
            reject(err); // error generating new access and refresh token because refresh token has expired
          });
      });
    },
    logoutUser(context) {
      if (context.getters.loggedIn) {
        return new Promise((resolve) => {
          axiosBase
            .post("/blacklist/")
            .then((response) => {
              localStorage.removeItem("access_token");
              localStorage.removeItem("refresh_token");
              context.commit("destroyToken");
              resolve(response);
            })
            .catch((err) => {
              localStorage.removeItem("access_token");
              localStorage.removeItem("refresh_token");
              context.commit("destroyToken");
              resolve(err);
            });
        });
      }
    },
  },
});

注销.vue

<template>
  <div>
    <h3>Log out page</h3>
    <v-btn small color="success" class="mr-2 mb-5" @click="logout">
      log out
    </v-btn>
  </div>
</template>

<script>
export default {
  name: "Logout",
  methods: {
    logout() {
      this.$store.dispatch("logoutUser").then(() => {
        this.$router.push({ name: "Home" });
      });
    },
  },
};
</script>
4

0 回答 0