Author: Little potato Biubiubiu

Blog Park: www.cnblogs.com/HouJiao/

The Denver nuggets: juejin. Cn/user / 243617…

Wechat public number: unknown treasure program yuan

The content of the author’s articles are from their own practice, if you feel helpful to you, you can like ❤️ to give an encouragement or leave valuable comments

preface

In the last article, we used token to implement a very basic user login authentication function.

This section needs to optimize the previous implementation: 1. Optimize AXIos: request encapsulation, authentication information encapsulation 2. Deregister 3. Set the expiration time of the token

Optimize axios

The optimization of AXIOS is to encapsulate AXIOS and separate a module, which is responsible for writing the API of the request. In the component, it only needs to call this API and pass in the corresponding parameters to realize the setting of authentication information when the request is sent.

// Code location: / SRC /utils/request.js
/* * @description: encapsulate axios request: http://www.axios-js.com/zh-cn/ * @version: 1.0.0 * @author: houjiaojiao * @date: 2020-07-23 16:32:19 * @LastEditors: houjiaojiao * @LastEditTime: 2020-09-01 17:30:46 */ 
import axios from 'axios'

// Create a new axios instance
let instance = axios.create({
  baseURL: '/api/cert/'});// Request interceptor
instance.interceptors.request.use(
  // Do something before sending the request
  request= > {
    // Add the Authorization field to each request header before sending the request
    const auth = 'Token ' + localStorage.getItem('token');
    request.headers.Authorization
    return request;
  },
  // Request an error to do something
  error= > {
    console.log('There are some problems with this request');
    console.log(error);
    return Promise.reject(error); })// Response interceptor
instance.interceptors.response.use(
  response= > {
    return response;
  },
  error= > {
    return Promise.reject(error); })// Encapsulate the GET request
export function get(url, params){
  return new Promise((resolve, reject) = > {
      instance.get(url, {
          params
        })
        .then(response= > {
          resolve(response);
        }).catch(error= > {
          reject(error)
        })
    
  })
}

// Encapsulate the POST request
export function post(url, params){
  return new Promise((resolve, reject) = > {
    instance.post(url, params)
      .then(response= > {
        resolve(response)
      }).catch(error= > {
        reject(error)
      })
  })
}

Copy the code

As you can see, we encapsulate axios’ GET and POST requests, and we define the Authorization field that needs to be added to the request header in AXIos’s request interceptor so that each request carries the header field.

We then wrap the request API, using login as an example.

// SRC/API /login.js
import {get, post} from '@/utils/request.js'

export const login = (loginForm) = > post('userAuth/login', loginForm)

Copy the code

We then invoke this API in the login component to initiate the request.

// Import the previously encapsulated API
import {login} from '@/api/login.js'

export default {
    name: 'Login'.data() {
        return {
            loginForm: {
                username: ' '.password: ' ',}}},methods: {
        login: function(){
            // Call the API directly
            login(this.loginForm).then(res= > {
                const {result, detail, errorInfo}  = res.data;
                if(result == true) {// The login succeeds
                    localStorage.setItem('token', detail.token);
                    // Jump to the page
                    this.$router.push('/certMake');
                }else{
                    this.$message({
                        showClose: true.message: errorInfo,
                        type: 'error'}); }})}}}Copy the code

The code in template in the login component is omitted above

Finally, enter the user name and password in the login interface, you can log in normally.

We then click on other pages in the browser and see that each request header that is issued carries the Authorization field.

The cancellation

When the user clicks logout, all we should do is clear the locally saved token.

logout: function(){
  / / remove the token
  localStorage.removeItem("token");
  The path of the login page configured in router.js is'/'.
  this.$router.push("/");
}
Copy the code

After that, if we manually enter a URL into the browser and go to a page, we’ll see the response appear 401.

In this case, users can access the login page only when they log in to the page again.

For the 401 returned after logging out above, it would actually be more reasonable to jump directly to the login page. Therefore, we also need to make a judgment on the token before sending a request. If no token exists, we will directly jump to the login page.

The functionality described above is defined in router.js using the guard navigation implementation code

// Define a front-facing global guard for the route
router.beforeEach((to, from, next) = > {
    let token = localStorage.getItem('token');
    if(token){
        // Token exists Access login The page for creating a product certificate is displayed
        if(to.path == '/' || to.path  == '/login'){
            next('/certMake');
        }else{ next(); }}else{
    	// Token does not exist path '/' is the path set on the login page
        if(to.path === '/'){
            next();
        }else{
            next('/')}}})Copy the code

Setting the Token Validity Period

The login function we completed before, in addition to the need to log in after logout, any other time as long as the user successfully logged in once, do not need to log in here. There is a big security risk, that is, when the user’s token is accidentally leaked, others can operate our page without restrictions.

Therefore, the best way is to set a validity period for the token. When the validity period expires, the user is forced to log out and a new token is generated at the next login.

Then the following is the code implementation of this function.

The token validity period is configured on the back-end

The backend creates a auth.py under the userAuth module, defines a user authentication class, inherits TokenAuthentication, and implements token expiration processing.

# -*- coding: utf-8 -*-
# Create your views here.

from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions
from django.utils import timezone
from datetime import timedelta
from django.conf import settings

# Token expiration time processing
class ExpiringTokenAuthentication(TokenAuthentication) :
    def authenticate_credentials(self, key) :
        model = self.get_model()
        try:
            token = model.objects.select_related('user').get(key=key)
        except model.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token.')
        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted.')
        A Token expired after the Token expired
        # if the current time is greater than the Token creation time +DAYS, then the Token has expired
        if timezone.now() > (token.created + timedelta(days=7)) :print "Token has expired"
            The response is 401 after expiration
            raise exceptions.AuthenticationFailed('Token has expired')
        return (token.user, token)

Copy the code

The validity period of the token is set to 7 days

And then modify the setting in the configuration of the global certification scheme for our custom ExpiringTokenAuthentication user authentication.

Set the global authentication scheme
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',),'DEFAULT_AUTHENTICATION_CLASSES': (
        'userAuth.auth.ExpiringTokenAuthentication'.# Token expiration time
        # # 'rest_framework. Authentication. TokenAuthentication', token authentication)}Copy the code

Then we define the logics for logging out in userAuth module views.py: delete the tokens in the database when logging out.

@api_view(['GET'])
@permission_classes((AllowAny,))
@authentication_classes(())
def logout(request) :
    """ Log out """
    result = True
    errorInfo = u''
    detail = {}
    token = ' '
    authInfo = request.META.get('HTTP_AUTHORIZATION')
    if authInfo:
        token = authInfo.split(' ') [1]
    try:
        Delete the token
        tokenObj = Token.objects.get(key=token)
        tokenObj.delete()
    except Exception as e:
        traceback.print_exc(e)
        print 'token not exist'
        result = False
        errorInfo = U 'Logout failed'
    return Response({"result": result, "detail": {}, "errorInfo": errorInfo})
Copy the code

The front set

After the token expires, the backend will return 401, so we need to process the 401 in the response interceptor. That is, when the backend response is 401, a pop-up box will prompt the user to log out.

// Response interceptor
instance.interceptors.response.use(
  response= > {
    return response;
  },
  error= > {
    // The token expiration logic is handled here
    // After the token expires, 401 is returned
    if(error.response.status == 401){
      MessageBox.confirm('Login expired, please log in again'.'Sure to log out', {
        confirmButtonText: 'Log in again'
        type: 'warning'
      }).then(() = > {
        // Call the interface to log out
        get('/userAuth/logout').then( response= > {
          // Remove tokens cached locally
          localStorage.removeItem("token"); location.reload(); })})}return Promise.reject(error); })Copy the code

The results demonstrate

Now that the logic is done on the back end, let’s demonstrate the final result.

First let’s look at the creation time of the existing tokens in the database.

It can be seen that the creation time of the existing token in the database is 2020-09-17, and the current time is 2020-10-10, which has exceeded the validity of the token.

The validity period of the token is set to 7 days

Then let’s refresh the page.

A dialog box is displayed to force the user to log in again.

After clicking the Logout button, the user will request the logout interface of the backend, and the existing tokens in the database will be deleted. After the deletion, the tokens cached locally in localStorage will also be deleted. Finally, the user will jump to the login page of the product.

The token in the database has been deleted

Then enter the username and password on the login page to log in again and you will find that the token in the database has been updated.

The last

That concludes this article series on VUE combining Django-Rest-FrameWord for Login Authentication.

The article is the actual combat operation, I hope to give you a reference.

The index

Vue Combines Django-REst-FrameWord to Implement Login Authentication (part 1)

Refer to the article

👉 Django-REst-Framework official documentation # Permission document 👉 Django-REst-Framework official documentation # Authorization document

Write in the last

If this article helps you, ❤️ follow + like + favorites + comment + forward ❤️ to encourage the author

Article public number first, focus on unknown treasure program yuan for the first time to get the latest article

Ink ❤ ️ ~