Analysis of gin-contrib/session source code

Initial code:

redis.NewStore is used to configure the redis connection, and the last parameter is used as the encryption key to encrypt the sessionid.

image-20210604015357008

The first is that the sessions.Sessions method returns an httphandler middleware. All requests share the same store, that is, share the same underlying storage.

image-20210604015423756

Next, obtain the value corresponding to the count key in the session server information through session.Get("count"). The Get method is as follows:

image-20210604015848922

The Session method is defined as follows:

image-20210604015919522

The following method is defined in the redistore.go file

image-20210604005509237

This code is called by the session.Sessions() method. The method returns the sessions.Session structure. The structure is defined as follows. The name in the structure is the name of the session, and Values ​​is the key-value pair stored on the server corresponding to the session-name. User-defined information in the form of. Options are cookie options, such as Domain, Path, Expires, HttpOnly, etc. cookie configuration options, store is the underlying storage of session, and the current analysis is corresponding to redis.

// Session stores the values and optional configuration for a session.
type Session struct {
	// The ID of the session, generated by stores. It should not be used for
	// user data.
	ID string
	// Values contains the user-data for the session.
	Values  map[interface{}]interface{}
	Options *Options
	IsNew   bool
	store   Store
	name    string
}

Here is the actual cookie in the browser to help understand:

image-20210604011807331

Back to the Get method above, first call the sessions.GetRegistry® method, the GetRegistry® method is as follows:

image-20210604010851584

This code first calls the Get method in github.com/gorilla/context to determine whether the request carries a key-value pair whose key is registryKey. The Registry structure contains a member request and a mapping session. This mapping contains the session name and One-to-one correspondence of the above Session structure. In other words, a request can correspond to multiple sessions, and these sessions have different names or sessionids. This structure can be simply understood as a request session management module that maintains different sessions requested by a request. Here is a little question, why does a request have a different session? I realized that because a request can have multiple session-ids, a session-id is in the form of a cookie, and a user can have multiple session-ids to obtain different user information, for example, session-userinfo is used Login verification, session-articlelike is used to get user’s article like information. Here is an example:

image-20210604014042059

Back to the code analysis,

If the above key-value pair does not exist in the request, the structure is created and the key-value pair is included in the request, and the structure is returned.

Next, call the Get method of the Registry structure in the Get method,

image-20210604011540546

As you can see, this method first judges whether the session-name is legal, if it is not legal, it returns directly, then it judges whether the key is already included in the Registry, and if it does, it returns the corresponding value directly, which is the Session structure above. Session.Values ​​can get session custom information. If this key is not included, go to the store.New method.

image-20210604005309959

This code is the code that creates the Session structure. If the request contains the cookie value corresponding to the name, the actual ID value of the session is obtained by secure decryption, and then the ID is passed from the redis cache through s.load(session) The value is session.ID to find the corresponding custom session information and fill it in the session.values ​​mapping.

image-20210604014930899

This code is the specific load method. It is very simple. It is to obtain the redis connection from the redis connection pool and then query the key-value pair data through the Get command, and then deserialize it and store it in the values ​​field of the session structure.

image-20210604015105270

So the whole process above is the process of reading the corresponding value of a key. Think about it. At the beginning, the user first initiates a get request, and the process goes to the store.New method. At this time, the request sent by the browser does not contain the session cookie, so it directly returns a Session structure with no key in the values ​​member. Correct. At this time, the above session.Get("count") is nil.

image-20210604020724618

Use a picture to visually summarize the above process:

image-20210604092249615

Next, call the session.Set("count", count) method.

image-20210604092428108

This method is to directly store the user-defined sessioninfo key-value pair into the values ​​mapping of the sessions.Session structure. At this time, it has not been persisted to the Redis cache.

Next, call the session.Save() method to persist the key-value pairs in values ​​to redis.

image-20210604092624569

The process of s.Session() is consistent with the above, so I won't repeat it. Take a look at the Save method:

image-20210604092808335

Call the Save method in redistore.go:

image-20210604093017575

If the cookie corresponding to the Session expires, the corresponding cookie is recreated and returned; if the cookie corresponding to the Session is not expired, a random sessionid is generated first, and then s.save(session) is called to map the values ​​in the session structure Key-value pairs are persisted in the redis cache. Then the sessionID is encrypted and encoded with a key and set into the set-cookie field of the request response. The following is the definition of the save method. It is to store the session-id and the serialized user-defined key-value pair string in the redis set.

image-20210604093529955