gin-contrib/session源码浅析

初始代码:

redis.NewStore用于配置redis连接,最后一个参数作为加密密钥对sessionid进行加密处理。

image-20210604015357008

首先是sessions.Sessions方法返回一个httphandler中间件,所有的请求共享相同的store,即共享相同的底层存储。

image-20210604015423756

接下来通过session.Get(“count”)获取session服务端信息中count键对应的值,Get方法如下:

image-20210604015848922

Session方法定义如下:

image-20210604015919522

下面的这个方法定义在redistore.go文件中

image-20210604005509237

这段代码被session.Sessions()方法调用,方法返回sessions.Session结构体,该结构体定义如下,结构体中的name就是session的名称,Values就是session-name对应的服务端存储的键值对形式的用户自定义信息。Options是cookie选项,如Domain, Path, Expires, HttpOnly等等cookie配置选项,store是session底层存储,当前分析的是对应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
}

这里给出实际的浏览器中的cookie帮助理解:

image-20210604011807331

回到上面的Get方法,首先调用sessions.GetRegistry®方法,GetRegistry®方法如下所示:

image-20210604010851584

这段代码首先调用了github.com/gorilla/context中的Get方法,判断请求中是否携带键为registryKey的键值对,Registry结构体包含一个成员request和一个映射sessions,这个映射中包含session名称和上述Session结构体的一一对应关系。也就是说,一个request请求可以对应多个session,这些session有不同的名称或者说sessionid。这个结构体可以简单理解为是一个请求的session管理模块,维护着一个request请求的不同session。这里有个小小的疑问,为啥一个request请求会有不同的session呢?我悟了,因为一个请求本来就可以有多个session-id,一个session-id形式上就是一条cookie,用户可以有多个session-id分别用来获取不同的用户信息,比如session-userinfo用于登录校验,session-articlelike用于获取用户文章点赞信息。 下面是个例子:

image-20210604014042059

回到代码分析中来,

如果请求中不存在上述键值对则创建该结构体并将键值对包含到请求当中,并返回该结构体。

接下来在Get方法中调用Registry结构体的Get方法,

image-20210604011540546

可以看到,这个方法首先判断session-name是否是合法的,如果不合法直接返回,接下来判断Registry中是否已经包含这个键,如果包含就直接返回对应的值,就是上面的Session结构体,通过Session.Values就能获取到session自定义信息。如果不包含这个键,就进到store.New方法。

image-20210604005309959

这段代码是创建Session结构体的代码,如果request请求中携带有该name对应的cookie值,则安全解密获得session实际的ID值,接下来通过s.load(session)从redis缓存中通过该ID值即session.ID查找到对应的自定义session信息并填充到session.values映射中。

image-20210604014930899

这段代码就是具体的load方法,很简单,就是从redis连接池中获取redis连接然后通过Get命令查询键值对数据,然后反序列化存储到session结构体的values字段中。

image-20210604015105270

所以上面的整个过程就是读取一个键对应值的过程。思考一下,一开始用户首先发起一个get请求,流程一直走到store.New方法,这个时候浏览器发送的请求中不包含session cookie,因此直接返回一个Session结构体,其中的values成员中没有键值对。此时上述session.Get(“count”)就为nil。

image-20210604020724618

用一张图来形象一点地概括上述流程:

image-20210604092249615

接下来就调用session.Set(“count”, count)方法。

image-20210604092428108

这个方法就是直接用户自定义的sessioninfo键值对存到sessions.Session结构体的values映射中。此时还没有持久化到Redis缓存中。

接下来调用session.Save()方法将values中的键值对持久化到redis。

image-20210604092624569

s.Session()过程与上述一致,不再赘述。看一下Save方法:

image-20210604092808335

调用redistore.go中的Save方法:

image-20210604093017575

如果Session对应的cookie过期了则重新创建对应的cookie,并返回;如果Session对应的cookie没有过期,就首先生成随机的sessionid,然后调用s.save(session)将session结构体中的values映射中的键值对持久化到redis缓存中。然后将sessionID使用密钥加密并编码后设置到请求响应的set-cookie字段中。下面是save方法的定义。就是将session-id和序列化后的用户自定义键值对字符串存到redis set中。

image-20210604093529955

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值