Recently I made a list of myself, Ummm… The list goes something like this:

  • React SSR server rendering
  • JWT user authentication
  • Vue buckets
  • Wechat small program development
  • . , etc.

Well, I can’t complain. One at a time. Just recently read some token to do identity authentication articles, found that most of them are said token login how how good, anyway, there are few serious really achieve… Just in time, in accordance with the principle that I am a little white and I am afraid of who, continue to share express + JWT pit filling experience. Why is the title named lightest practice? Because after reading this you can get a general idea of the benefits of token login and how to simply implement a small system of token authentication on the back end. This demo was run on the same scaffold as my first post (—–> express-React-scaffold). The implementation looks like this:

  • The page without token authentication can be viewed normally
  • Token authentication is performed on the page that needs to be verified
  • There is no token information or the token information is expired. The user is prompted to log in again. The login page is displayed
  • After a successful login, each request carries token information

This article includes

  • Why use tokens for authentication (the other mode is Session)
  • Setup of the front-end HTTP request interceptor
  • Back-end Express + JsonWebToken implements token based user authentication

What is a token

Two ways of identity authentication

In a system that separates the front and rear ends, identity authentication is very important. Currently, the following two identity authentication modes are commonly used:

  • Cookie-based server authentication, known as session, generates session data related to the user on the server, and sends sesssion_id to the client to store in the cookie. In this way, the client request with session_id can verify whether the session data exists on the server side, so as to complete user authentication.
  • Token based Token based user authentication is a stateless authentication mode on the server. The server does not need to store Token data. After the user is authenticated, the server generates a token(hash or encrypt) and sends it to the client. The client can place the token in a cookie or localStorage(sessionStorage) and put the token in the Header of each request. After receiving the token, the server can confirm the user’s identity.

Benefits of token authentication

  • Small size (a string of characters), therefore fast transmission
  • There are various transmission modes, such as HTTP headers (recommended), URLS, and POST parameters. Payload itself (in payload) contains all user-related authentication messages, such as the user’s access route, access validity period and other information. The server does not need to connect to the database to verify the validity of the information. In addition, payload supports cross-domain authentication for application customization and is mostly applied to single sign-on, which fully relies on stateless APIS. Fit RESTful Design principles (stateless HTTP)
  • After a user logs in, the server returns a string of tokens and stores them locally (i.e. on the client). After that, all subsequent visits to the server must carry this string of tokens to gain access to server-related routes, services, and resources. Easy to implement CDN, static resources distributed management
  • In traditional session authentication, the server must save the session ID for cookie authentication with the user. Initially, the sessionID is stored on only one server. Therefore, only one server can respond to the sessionID. Even if other servers are idle, they cannot respond to the sessionID. JWT relies on storing authentication information locally on the client and does not need to use information stored by the server to authenticate, so any server can respond and the server’s resources are better utilized.
  • Good support for native mobile applications Native mobile applications do not support cookies and sessions well, but support tokens well.

The composition of JWT

The essence of JWT is actually a string with three parts: header + payload + signature.

// Header
{
  "alg": "HS256",// The signature algorithm used"typ": "JWT"} // Payload {// The issuer of the JWT"iss": "luffy"// When was this JWT issued"iat":1441593502, // When is this a time stamp"exp": 1441594722, // The party receiving JWT"aud":"www.youdao.com", // The user that JWT is aimed at"sub":"[email protected]"Above are some fields defined by the JWT standard. In addition, some fields can be defined privately"form_user": "fsdfds"} // The Signature is used after base64 encoding the above two objects. Then the signature is formed by using HS256 algorithm encryption, which usually requires a key provided by us, such as secretKey:'name_luffy'
const base64url = require('base64url')

const base64header = base64url(JSON.stringify(header));
const base64payload = base64url(JSON.stringify(payload));
const secretKey = 'name_luffy';
const signature = HS256(`${base64header}.${base64payload}`,secretKey); // Finally we form the JWT we need: const JWT = base64header +"." + base64payload + "."+ signature; // It looks like this:  // eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7 ItqpKViMCopy the code

How JWT works

I took down from the official website jwt. IO diagram to show, is the following process, said very detailed, in addition to some details, such as what form of storage, where to put the head, where to store the client, etc., the official website has a more detailed introduction, you can have a look.

How does the front and back end use this thing for identity authentication

Train of thought

The next step is to explain how to use JWT to authenticate the front and back ends. The specific ideas are as follows:

  • The logic of user login registration does not require authentication, because there is no user identity information and login status;
  • After a user logs in, the back end generates a token and returns it to the front end. After the front end gets the token, the token is cached locally. The localStorage can also be a cookie for subsequent use.
  • Other content involving front and back end interaction requires the front-end to put the authentication token information in the request header to the back end
  • After receiving the request, the backend checks the token first. If the token is valid (that is, the token is correct and has not expired), it executes next(). Otherwise, it returns 401 and the corresponding message.

Implementation details of token login

  • Back end: Express-JWT + JSONWebToken First, install two packages
yarn add express-jwt jsonwebtoken 
Copy the code

The token is then generated in the login process and returned to the front end

// /routes/user.js
if(user ! == null) {// After the user successfully logs in, the token is generated and returned to the front-endletToken = jwt.sign(tokenObj, secretKey, {expiresIn: 60 * 60 * 24 // authorized period 24 hours}); res.json({ success:true,
        message: 'success',
        token: token
  });
} 
Copy the code

Secondly, set up the middleware that intercepts the token, including token validation and error message return:

// jwt.js,token middleware const expressJwt = require("express-jwt");
const { secretKey } = require('.. /constant/constant'); // Express-JWT middleware automatically does token validation and error handling for us, so normally we can write it in the format where unless is the API that you want not to verify the token. const jwtAuth = expressJwt({secret: secretKey}).unless({path: ["/api/user/login"."/api/user/register"]}); 

module.exports = jwtAuth;
Copy the code
// constant.js // set the password salt value and token secretKey const crypto = require('crypto');

module.exports = {
  MD5_SUFFIX: 'luffyZhou I am a fixed length salt value ',
  md5: (pwd) = > {let md5 = crypto.createHash('md5');
    return md5.update(pwd).digest('hex');
  },
  secretKey: 'luffy_1993711_26_jwttoken'
};
Copy the code

Finally, put JWT middleware in front of the routing middleware

Route.use (jwtAuth); // routes/index.js // Routing middleware router.use((req, res, next) => {// any routing information will execute the statement console.log('this is a api request! '); // Pass it to the next middleware. Note that the middleware registration order is next(); });Copy the code

The back-end logic is complete, and now the implementation of the front end.

  • Front end: The Axios interceptor + localStorage storage token front end mainly does two things:

First, the login after the successful return of the token client, you can use localStorage can also use cookies, I see the official recommendation to use localStorage, I will use localStorage. Second, each request puts the token in the Authorization field of the header header.

// The axios interceptor intercepts the request, Gives all the request token axios. Interceptors. Request. Use request (= > {const luffy_jwt_token = window. The localStorage. The getItem ('luffy_jwt_token');
  if(luffy_jwt_token) {// request. Headers ['Authorization'] =`Bearer ${luffy_jwt_token}`;
  }
  returnrequest; }); / / intercept response, meet law of token out error axios. Interceptors. Response. Use (response = > {if (response.data.token) {
      console.log('token:', response.data.token);
      window.localStorage.setItem('luffy_jwt_token', response.data.token);
    }
    return response;
  },
  error => {
    const errRes = error.response;
    if (errRes.status === 401) {
      window.localStorage.removeItem('luffy_jwt_token');
      swal('Auth Error! ', `${errRes.data.error.message}, please login! `,'error')
      .then(() => {
        history.push('/login');
      });
    }
    returnPromise.reject(error.message); // Return the error message returned by the interface});Copy the code

Request. Headers [‘Authorization’] must be set in this form, otherwise the backend will have problems even if it receives fields. Return 401, request. Headers. Authorization or request. The headers. The Authorization can be set up is successful, the browser view there is no problem, but in the back end to 401 and the back-end all can only attain lowercase, Namely res. Headers. Authorization, the back-end in capital gain is undefined.

conclusion

Very simple a small chestnut, there is no technical content of the article, when writing to play practice writing. Where else is the code? Add login registration and token authentication on express-react-scaffold. You can use /login to access the login part of the logic and token authentication function. O ha ha ~ O (studying studying)