preface

The Todo List project has reached a very important part here, involving the user part. Permissions and multi-party cooperative operation are all very important and complicated, so this section is divided into several chapters and completed step by step.

This chapter focuses on user login and session registration.

Todo List GitHub code library

This “Todo List: Vue To-do List Task Management”, divided into chapters, interested students can continue to pay attention to.

Chapter 1: Introduction (Project construction, implementation of basic functional components)

Chapter 2: Data dynamic processing (localStorage + Vuex), can be added, can be edited

Chapter 3: To-do list custom grouping

Chapter 4: To-do List Add descriptions, pictures and other information

Chapter 5: Node + Express builds server connection to Mysql

Chapter 6: Client and Server interaction, to-do task entry, etc

Chapter 7: Multi-person collaborative processing of to-do items, authority management

Chapter 8: Closure: Online release

Eight chapters are initially defined, and may be added or reduced in actual development.

The Client side

New pages/ User directory, which stores user related pages, such as login, registration, user information, etc.

/user/login.vue

< div id = "login" v - if = "type = = 'login'" > < div class = "form" > < h1 > user login < / h1 > < div class = "c - input" > < label for = "" > < / label > user name <input type="text" V-model ="username" placeholder=" please input username" > </div> <div class="c-input"> <label for=""> password </label> < INPUT Type ="password" V-model ="password" placeholder=" please input password" > </div> <div class="c-input"> </label> < INPUT @click="login"> </div> </div> </div> <div id="register" V-else > <div class="form"> <h1> <div class="c-input"> <label for=""> username </label> <input type="text" v-model="username" Placeholder =" please input username "> </div> <div class="c-input"> <label for=""> password </label> <input type="password" V-model ="password" Placeholder =" input password" > </div> <div class="c-input"> <label for=""> </label> <input type="password" v-model="password2" Placeholder =" input password "> </div> <div class="c-input"> </label> <input class=" BTN "type="button" value=" placeholder" @click="register"> </div> </div> </div>Copy the code

Corresponding JS method

login () {
  let vm = this
  vm.$store.dispatch(types.A_LOGIN, {
    username: vm.username,
    password: vm.password
  }).then((data) = > {
    vm.$router.push({
      name: 'TodoList'})},(err) = > {
    console.log(err)
  })
},
register () {
  let vm = this
  vm.$store.dispatch(types.A_REGISTER, {
    username: vm.username,
    password: vm.password,
    password2: vm.password2
  }).then(() = > {
    vm.$router.push({
      name: 'Login'.query: {
        type: 1}})})}Copy the code

/store/actions.js

[types.A_REGISTER] ({ commit, dispatch }, params) {
  http({
    method: 'POST'.url: '/user/register'.json: true.data: params
  }).then(() = > {
  })
},
[types.A_LOGIN] ({ commit, dispatch }, params) {
  return http({
    method: 'POST'.url: '/user/login'.json: true.data: params
  }).then((resp) = > {
    return Promise.resolve(resp)
  }, (err) = > {
    return Promise.reject(err)
  })
}
Copy the code

/commons/http.js

// Set the default value of the configuration when creating the instance
var instance = axios.create({
  baseURL: '/api'.headers: {
    'Content-Type': 'application/json; charset=UTF-8'
  },
  timeout: 60000 // Set the timeout to 1 minute
})

// Add request interceptor
instance.interceptors.request.use(function (config) {
  const headers = config.headers = config.headers || {}
  // What to do before sending the request
  let token = localStorage.getItem('x-token')
  headers['x-token'] = token
  if (config.json) {
    headers['Content-Type'] = 'application/json; charset=UTF-8'
    delete config.json
  }
  return config
}, function (error) {
  // What to do about the request error
  return Promise.reject(error)
})

// Add a response interceptor
instance.interceptors.response.use(function (response) {
  // What to do with the response data
  if (response.headers['x-token']) {
    localStorage.setItem('x-token', response.headers['x-token'])}return response
}, function (error) {
  // Do something about the response error
  let code = error.response.data.code
  switch (code) {
    case 1000:
      location.href = '/user/login? type=1'
      break
  }
  return Promise.reject(error)
})
Copy the code

In the request interceptor, we add the header X-Token, and in the response, we also obtain the X-Token, and intercept the error code. If it is 1000, it indicates that the token is invalid and the login is not done, and we jump to the login page.

We modified baseURL to address cross-domain issues, and we also modified the /config/index.js file under the root directory.

/config/index.js modify proxyTable to block all requests with ‘/ API ‘, target is the domain name of background interface address, pathRewrite is the URL re for modifying the address of request interface, and change/API to empty string.

proxyTable: {
  '/api': {
    target: 'http://localhost:3000'.changeOrigin: true.pathRewrite: {
      '^/api': ' '}}}Copy the code

The Server side

/server/sql.js add 2 SQL, login query and registration insert.

module.exports = {
  ...
  USER_LOGIN: "SELECT * FROM user where username = '${username}' and password = '${password}'".USER_REGISTER: "INSERT INTO user (username, password, ip, date) VALUES('${username}', '${password}', '${ip}', '${date}')"
}
Copy the code

/server/app.js installs 2 modules for user signature

npm i express-jwt jsonwebtoken -S
Copy the code
. app.set('superSecret'.'todolist'); // Set the app password -- the password used to generate the signature

/** * User login */
app.post('/user/login'.(req, res) = > {
  const params = req.body;
  console.log(params)
  if(! params.username){ sendError(res,'User name cannot be empty')
    return
  }
  if(! params.password){ sendError(res,'Password name cannot be empty')
    return
  }
  let username = params.username
  let password = params.password
  let cliendIp = utils.getClientIp(req)
  let csql = eval('`+sql.USER_LOGIN+'`);
  console.log('[SQL:]', csql);
  query(csql, (err, result, fields) = > {
    if (err) {
      console.log('[SELECT ERROR]:', err.message)
      return sendError(res, err.message)
    }
    result = JSON.stringify(result);
    result = JSON.parse(result);
    if(! result.length){return sendError(res, 'User information error')
    }
    result.map(item= >{
      delete item.password
    })
    let user = result[0];
    / / create a token
    var token = jwt.sign(user, app.get('superSecret'), {
      expiresIn : 60*60*24// The authorization period is 24 hours
    });
    user.token = token;
    // The request header returns
    res.header('x-token', token);

    res.send(user)
  })
})


/** * User registration */
app.post('/user/register'.(req, res) = > {
  const params = req.body;
  console.log(params)
  if(! params.username){ sendError(res,'User name cannot be empty')
    return
  }
  if(! params.password){ sendError(res,'Password name cannot be empty')
    return
  }
  if(params.password ! == params.password2){ sendError(res,'Password must be the same twice')
    return
  }
  let username = params.username
  let password = params.password
  let ip = utils.getClientIp(req)
  let date = moment().format('YYYY-MM-DD HH:mm:ss');
  let csql = eval('`+sql.USER_REGISTER+'`);
  console.log('[SQL:]', csql);
  query(csql, (err, result, fields) = > {
    if (err) {
      console.log('[SELECT ERROR]:', err.message)
      return sendError(res, err.message)
    }
    res.send(result)
  })
})

// All apiRoutes routing interfaces verify the token
var apiRoutes = express.Router();

apiRoutes.use(function(req, res, next) {
  var token = req.body.token || req.query.token || req.headers['x-token'];
  if (token) {      
    // Decode token (verify secret and check validity (exp))
    jwt.verify(token, app.get('superSecret'), function(err, decoded) {      
      if (err) {
        sendError(res, 'Token has expired'.1000)}else {
        // If the verification is successful, write the decryption result in req
        req.decoded = decoded;  
        next(); // Proceed to the next route}}); }else {
    // Failed to get token
    sendError(res, 'Please pass in token')}})// Get all tasks
apiRoutes.get('/task/get-task-list'.(req, res) = >{... })... app.use('/', apiRoutes);

Copy the code

conclusion

Here the user password is not encrypted operation, direct plaintext, login query, registration insert is also relatively simple, without too much verification, mainly examples, I hope to give you inspiration. Detailed code behind optimization, add it.

Todo List GitHub code library