Today, I encountered a weird problem with Koa, and then studied the implementation principle of KOA-Session carefully, refreshing my knowledge. So let’s start at the beginning. So let’s see how sessions work. Okay?

What is the Session

The Session mechanism is a solution for maintaining state on the server side. Because the server side can maintain state. The client also needs to save an identity. Therefore, session mechanism may need to resort to cookie mechanism to achieve the purpose of saving the identity.

  1. The server creates seesion on the server side when it receives the first access from the client, and then saves seesion(we can keep seesion in memory or in Redis, the latter is recommended), It then generates a unique identifier string for the session and plants this unique identifier string in the response header.
  2. The signature. This step uses the secret key to sign the SID, preventing the client from changing the SID. (Optional steps)
  3. When the browser receives a request, it parses the response header and stores the SID in a local cookie. The browser will send the cookie information of the domain name in the header of the next HTTP request.
  4. When the server receives the request from the client, it will resolve the SID in the cookie of the request header, and then find the session of the client saved by the server according to the SID, and determine whether the request is valid.

If the session data is stored on the server in the classical implementation, then the session is stored in memory, assuming no external storage device is used. So if once the server restarts all sessions disappear.

Eerie Koa – the session

Ok, so let’s see if koA-session can reproduce this problem.

const koa = require('koa')
const app = new koa()
const session = require('koa-session')

// Signature key keys is used to sign cookies
app.keys = ['some secret'];

/ / configuration items
const SESS_CONFIG = {
  key: 'kkb:sess'./ / cookie key name
  maxAge: 86400000.// Validity period, default is one day
  httpOnly: true.// Server only
  signed: true./ / signature cookies
};

/ / register
app.use(session(SESS_CONFIG, app));

/ / test
app.use(ctx= > {
  if (ctx.path === '/favicon.ico') return;
  / / to get
  let n = ctx.session.count || 0;
  / / set
  ctx.session.count = ++n;
  ctx.body = 'the first' + n + 'This visit';
});

app.listen(3000)

Copy the code

Count is added each time if the service is restarted. Count should go to zero. But it didn’t turn out that way.

Cause analysis,

At this time, let’s analyze it carefully. First, we noticed that the cookie field where SID was stored was eyXXXXX. It is most likely base64 encoded JSON. Not what we normally think of as a UUID.This result was confirmed by online Base64 decoding.So the problem is very clear. The original KOA-session does default by serializing the session and storing it on the client. We can also confirm this statement from the following NPM documentation.www.npmjs.com/package/koa…

The documentation explicitly states that koA stores unencrypted data on the client by default.

Advantages and disadvantages of client storage

advantages

First, the advantages. There are probably two advantages to client-side storage.

  • Low cost implementation of session persistence problem
  • Low cost implementation of multi-instance shared session problem

In general, if we implement persistent session and global sharing, we need to use third-party storage such as Redis or mongodb. Client-side serialization is a good solution to this problem. But using client-side storage is a good solution to this problem.

disadvantages

There are two drawbacks

  • Limited storage capacity (Cookie size is typically 4K)
  • Security issues Sensitive data cannot be stored because it is stored on the client side and is unencrypted.

How do I specify the storage mode

In koA-session, if you want to change the storage mode, you can implement the Store interface.

Memory implementation

First let’s write a basic memory implementation. Just to get familiar with the interface.

class Memory {
    constructor () {
        this.sotry = {}
    }
    
    get(key) {
        console.log('get:',key)
        return this.sotry[key]
    }

    set(key,sess) {
        console.log('set:',key,sess)
        this.sotry[key] = sess
    }
    destroy (key) {
        console.log('destroy:',key)
        this.sotry = {}
    }
}

const SESS_CONFIG = {
    key: 'kkb:sess'.store: new Memory() // Specify the implementation
}

app.use(session(SESS_CONFIG, app))
Copy the code

You can see that after the storage is specified, the KOA-session calls the getter and setter methods in the storage interface.

The browser does not store serialized data but only siDs, or Uuid.

The complete code

Github.com/su37josephx…

Redis implementation

Let’s also look at Redis storage methods commonly used in production environments.

const redisStore = require('koa-redis')
const redis = require('redis')
const redisClient = redis.createClient(6379.'localhost')

const wrapper = require('co-redis')
const client = wrapper(redisClient)

app.keys = ['some secret']

const SESS_CONFIG = {
    key: 'kkb:sess'./ / name
    store: redisStore({ client })
}

app.use(session(SESS_CONFIG, app))
Copy the code

conclusion

The default storage option for Koa is client-side serialization, refreshing our impression of Session convention. This approach actually borrows from the JWT Token implementation. Great for small applications. Persistence and scale-out problems can be solved very cheaply.

Identifying problems is an opportunity for improvement

Don’t forget to like favorites