cookie管理(1)

Manager的主体

package session

import (
    "fmt"
    "log"
    "net/http"
    "net/url"
    "sync"
    "time"
)

type Manager struct {
    cookieName  string
    lock        sync.Mutex
    provider    Provider
    maxlifetime int64
}

var (
    provides map[string]Provider = make(map[string]Provider)
)

func RegisterProvider(name string, provider Provider) {
    if nil == provider {
        panic("session: Register provider is nil")
    }
    if _, dup := provides[name]; dup {
        panic("session: Register called twice for provider " + name)
    }
    provides[name] = provider
}

func NewManager(providerName string, cookieName string, maxlifetime int64) (*Manager, error) {
    provider, ok := provides[providerName]
    if !ok {
        return nil, fmt.Errorf("sessions: unknown provider %q (forgotten import?)", providerName)
    }
    return &Manager{
        provider:    provider,
        cookieName:  cookieName,
        maxlifetime: maxlifetime,
    }, nil
}

var doStartGC sync.Once

func (manager *Manager) DoStartGC() {
    doStartGC.Do(func() {
        manager.doGC()
    })
}

func (manager *Manager) doGC() {
    manager.lock.Lock()
    defer manager.lock.Unlock()
    log.Println("manager gc ...")
    manager.provider.SessionGC(manager.maxlifetime)
    log.Println("manager gc done")
    time.AfterFunc(time.Duration(manager.maxlifetime)*time.Millisecond, func() {
        manager.doGC()
    })
}

func (manager *Manager) SessionStart(writer http.ResponseWriter, req *http.Request) (session Session) {
    manager.lock.Lock()
    defer manager.lock.Unlock()
    cookie, err := req.Cookie(manager.cookieName)
    if err != nil || cookie.Value == "" {
        sid := makeSessionId()
        session, _ = manager.provider.SessionInit(sid)
        http.SetCookie(
            writer,
            &http.Cookie{
                Name:     manager.cookieName,
                Value:    url.QueryEscape(sid),
                Path:     "/",
                HttpOnly: true,
                MaxAge:   int(manager.maxlifetime),
            },
        )
        return
    }
    sid, _ := url.QueryUnescape(cookie.Value)
    session, _ = manager.provider.SessionRead(sid)
    //log.Printf("Using old session <%v>", sid)
    return
}

func (manager *Manager) SessionDestroy(writer http.ResponseWriter, req *http.Request) {
    cookie, err := req.Cookie(manager.cookieName)
    if err != nil || cookie.Value == "" {
        return
    }
    manager.lock.Lock()
    defer manager.lock.Unlock()
    manager.provider.SessionDestroy(cookie.Value)
    http.SetCookie(
        writer,
        &http.Cookie{
            Name:     manager.cookieName,
            Path:     "/",
            HttpOnly: true,
            Expires:  time.Now(),
            MaxAge:   -1,
        },
    )
}

类别定义

package session

type Provider interface {
    SessionInit(sid string) (Session, error)
    SessionRead(sid string) (Session, error)
    SessionDestroy(sid string) error
    SessionGC(maxlifetime int64)
}

type Session interface {
    Set(key, value interface{}) error
    Get(key interface{}) interface{}
    Delete(key interface{}) error

    GetString(key 
    SessionID() string
}

以及生成sessionid的方式:

package session

import (
    "crypto/rand"
    "encoding/base64"
    "io"
    "log"
)

func makeSessionId() string {
    b := make([]byte, 32)
    if _, err := io.ReadFull(rand.Reader, b); err != nil {
        log.Println("abnormal rand read for generating session-id")
        return ""
    }
    return base64.URLEncoding.EncodeToString(b)
}

参考文章:
https://astaxie.gitbooks.io/build-web-application-with-golang/content/en/06.1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值