iris-session梳理

xiaoxiao2021-02-28  9

入口

api := iris.New() api.Adapt(gm.NewSession())

session的构造

func NewSession() sessions.Sessions { db := redis.New(rs.Config{Network: rs.DefaultRedisNetwork, Addr: config.Instance().Redis.Address, Password: config.Instance().Redis.Password, Database: "", MaxIdle: 0, MaxActive: 0, IdleTimeout: rs.DefaultRedisIdleTimeout, Prefix: "", MaxAgeSeconds: config.Instance().Redis.MaxAgeSeconds}) // optionally configure the bridge between your redis server mySessions := sessions.New(sessions.Config{Cookie: configs.GetSessionConfig().Cookie, Expires: configs.GetSessionConfig().Expires}) mySessions.UseDatabase(db) return mySessions }

MaxAgeSeconds //指的是session在数据库存的有效期 Expires //指的是session的有效期

回到刚才的api.Adapt(gm.NewSession()),装饰器

func (s *sessions) Adapt(frame *iris.Policies) { // for newcomers this maybe looks strange: // Each policy is an adaptor too, so they all can contain an Adapt. // If they contains an Adapt func then the policy is an adaptor too and this Adapt func is called // by Iris on .Adapt(...) policy := iris.SessionsPolicy{ Start: s.Start, Destroy: s.Destroy, } policy.Adapt(frame) func (s SessionsPolicy) Adapt(frame *Policies) { if s.Start != nil { frame.SessionsPolicy.Start = s.Start } if s.Destroy != nil { frame.SessionsPolicy.Destroy = s.Destroy } }

使用

调用context.Session(),获取到session对象

func (ctx *Context) Session() Session { policy := ctx.framework.policies.SessionsPolicy if policy.Start == nil { ctx.framework.Log(DevMode, errSessionsPolicyIsMissing.Format(ctx.RemoteAddr(), ctx.framework.Config.VHost).Error()) return nil } if ctx.session == nil { ctx.session = policy.Start(ctx.ResponseWriter, ctx.Request) } return ctx.session }

如果session==nil,就会调用start

func (s *sessions) Start(res http.ResponseWriter, req *http.Request) iris.Session { var sess iris.Session cookieValue := GetCookie(s.config.Cookie, req) if cookieValue == "" { // cookie doesn't exists, let's generate a session and add set a cookie sid := SessionIDGenerator(s.config.CookieLength) sess = s.provider.Init(sid, s.config.Expires) cookie := &http.Cookie{} // The RFC makes no mention of encoding url value, so here I think to encode both sessionid key and the value using the safe(to put and to use as cookie) url-encoding cookie.Name = s.config.Cookie cookie.Value = sid cookie.Path = "/" if !s.config.DisableSubdomainPersistence { requestDomain := req.URL.Host if portIdx := strings.IndexByte(requestDomain, ':'); portIdx > 0 { requestDomain = requestDomain[0:portIdx] } if IsValidCookieDomain(requestDomain) { // RFC2109, we allow level 1 subdomains, but no further // if we have localhost.com , we want the localhost.cos. // so if we have something like: mysubdomain.localhost.com we want the localhost here // if we have mysubsubdomain.mysubdomain.localhost.com we want the .mysubdomain.localhost.com here // slow things here, especially the 'replace' but this is a good and understable( I hope) way to get the be able to set cookies from subdomains & domain with 1-level limit if dotIdx := strings.LastIndexByte(requestDomain, '.'); dotIdx > 0 { // is mysubdomain.localhost.com || mysubsubdomain.mysubdomain.localhost.com s := requestDomain[0:dotIdx] // set mysubdomain.localhost || mysubsubdomain.mysubdomain.localhost if secondDotIdx := strings.LastIndexByte(s, '.'); secondDotIdx > 0 { //is mysubdomain.localhost || mysubsubdomain.mysubdomain.localhost s = s[secondDotIdx+1:] // set to localhost || mysubdomain.localhost } // replace the s with the requestDomain before the domain's siffux subdomainSuff := strings.LastIndexByte(requestDomain, '.') if subdomainSuff > len(s) { // if it is actual exists as subdomain suffix requestDomain = strings.Replace(requestDomain, requestDomain[0:subdomainSuff], s, 1) // set to localhost.com || mysubdomain.localhost.com } } // finally set the .localhost.com (for(1-level) || .mysubdomain.localhost.com (for 2-level subdomain allow) cookie.Domain = "." + requestDomain // . to allow persistence } } cookie.HttpOnly = true // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge>0 means Max-Age attribute present and given in seconds if s.config.Expires >= 0 { if s.config.Expires == 0 { // unlimited life cookie.Expires = CookieExpireUnlimited } else { // > 0 cookie.Expires = time.Now().Add(s.config.Expires) } cookie.MaxAge = int(cookie.Expires.Sub(time.Now()).Seconds()) } // encode the session id cookie client value right before send it. cookie.Value = s.encodeCookieValue(cookie.Value) AddCookie(cookie, res) } else { cookieValue = s.decodeCookieValue(cookieValue) sess = s.provider.Read(cookieValue, s.config.Expires) } return sess }

再设置cookie.Domain的时候,req.URL作为服务端的时候,是没有Host信息的,所以cookie.Domain 会默认空串。

再看s.provider.Init

// Init creates the session and returns it func (p *provider) Init(sid string, expires time.Duration) iris.Session { newSession := p.newSession(sid, expires) p.mu.Lock() p.sessions[sid] = newSession p.mu.Unlock() return newSession }

init的时候做了两件事: 1.newSession 2.将session存到p.sessions里面

// newSession returns a new session from sessionid func (p *provider) newSession(sid string, expires time.Duration) *session { sess := &session{ sid: sid, provider: p, values: p.loadSessionValues(sid), flashes: make(map[string]*flashMessage), } if expires > 0 { // if not unlimited life duration and no -1 (cookie remove action is based on browser's session) time.AfterFunc(expires, func() { // the destroy makes the check if this session is exists then or not, // this is used to destroy the session from the server-side also // it's good to have here for security reasons, I didn't add it on the gc function to separate its action p.Destroy(sid) }) } return sess }

这里可以看到在配置文件中设置的expire 是用来起了一个定时任务,之后删掉这个session

func (p *provider) Destroy(sid string) { p.mu.Lock() if sess, found := p.sessions[sid]; found { sess.values = nil sess.flashes = nil delete(p.sessions, sid) p.updateDatabases(sid, nil) } p.mu.Unlock() }

destory的时候: 如果没有删除: 1.从p.sessions里面删除 2.更新到数据库

转载请注明原文地址: https://www.6miu.com/read-1400186.html

最新回复(0)