草庐IT

mongodb - 在 mongodb golang 中保存 session

coder 2024-07-07 原文

我在后端使用 golang,我的数据库是 mongodb。 我想将我的 Web 应用程序的用户 session (登录和注销之间)存储在 mongodb 中以实现持久性。由于提供程序仅适用于 mysql 而不是适用于 mongodb,我对其进行了编辑以支持 mongodb。但是当我尝试使用它时我得到无效的内存地址或零指针取消引用。 代码如下,如果有更好的编码方式请告知,谢谢

type (
    SessionStore struct {
        c      *mgo.Session
        sid    string
        lock   sync.RWMutex
        values map[interface{}]interface{}
    }
)

var mgopder = &Provider{}

func (st *SessionStore) Set(key, value interface{}) error {
    st.lock.Lock()
    defer st.lock.Unlock()
    st.values[key] = value
    return nil
}

// Get value from mongodb session
func (st *SessionStore) Get(key interface{}) interface{} {
    st.lock.RLock()
    defer st.lock.RUnlock()
    if v, ok := st.values[key]; ok {
        return v
    }
    return nil
}

// Delete value in mongodb session
func (st *SessionStore) Delete(key interface{}) error {
    st.lock.Lock()
    defer st.lock.Unlock()
    delete(st.values, key)
    return nil
}

// Flush clear all values in mongodb session
func (st *SessionStore) Flush() error {
    st.lock.Lock()
    defer st.lock.Unlock()
    st.values = make(map[interface{}]interface{})
    return nil
}

// SessionID get session id of this mongodb session store
func (st *SessionStore) SessionID() string {
    return st.sid
}

// SessionRelease save mongodb session values to database.
// must call this method to save values to database.
func (st *SessionStore) SessionRelease(w http.ResponseWriter) {
    defer st.c.Close()
    b, err := session.EncodeGob(st.values)
    if err != nil {
        return
    }
    st.c.DB("Employee").C("Sessions").Update(nil, bson.M{"$set": bson.M{
        "session_data":   b,
        "session_expiry": time.Now().Unix(),
        "session_key":    st.sid,
    },
    },
    )

    /*st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?",
    b, time.Now().Unix(), st.sid)*/
}

type Provider struct {
    maxlifetime int64
    savePath    string
    Database    string
}

// connect to mongodb
func (mp *Provider) connectInit() *mgo.Session {
    ds, err := mgo.Dial("Employee")
    if err != nil {
        return nil
    }
    return ds
}

// SessionInit init mongodb session.
// savepath is the connection string of mongodb
func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error {
    mp.maxlifetime = maxlifetime
    mp.savePath = savePath
    mp.Database = "Employee"
    return nil
}

// SessionRead get mysql session by sid
func (mp *Provider) SessionRead(sid string) (session.Store, error) {
    var sessiondata []byte
    ds := mp.connectInit()
    defer ds.Close()
    c := ds.DB(mp.Database).C("Session")
    err := c.Find(bson.M{
        "session_key": sid,
    }).Select(bson.M{"session_data": 1}).All(&sessiondata)
    if err != nil {
        if err.Error() == "not found" {
            c.Insert(bson.M{
                "session_key":    sid,
                "session_data":   " ",
                "session_expiry": time.Now().Unix(),
            })
        }
    }

    var kv map[interface{}]interface{}
    if len(sessiondata) == 0 {
        kv = make(map[interface{}]interface{})
    } else {
        kv, err = session.DecodeGob(sessiondata)
        if err != nil {
            return nil, err
        }
    }
    rs := &SessionStore{c: ds, sid: sid, values: kv}
    return rs, nil
}

// SessionExist check mongodb session exist
func (mp *Provider) SessionExist(sid string) bool {
    var sessiondata []byte
    ds := mp.connectInit()
    defer ds.Close()
    c := ds.DB("Employee").C("Sessions")
    err := c.Find(bson.M{
        "session_key": sid,
    }).Select(bson.M{
        "session_data": 1,
    }).One(&sessiondata)
    if err != nil {
        if err.Error() == "not found" {
            return false
        }
    }
    return true

}

// SessionRegenerate generate new sid for mysql session
func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
    var sessiondata []byte
    ds := mp.connectInit()
    defer ds.Close()
    c := ds.DB("Employee").C("Sessions")
    err := c.Find(bson.M{
        "session_key": oldsid,
    }).Select(bson.M{
        "session_data": 1,
    }).One(&sessiondata)
    if err != nil {
        if err.Error() == "not found" {
            c.Insert(bson.M{
                "sessoin_key":    oldsid,
                "session_data":   " ",
                "session_expiry": time.Now().Unix(),
            })
        }
    }
    /*  row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)

        err := row.Scan(&sessiondata)

    c.Update(bson.M{"sessoin_key": oldsid}, bson.M{
        "$set": bson.M{
            "session_key": sid,
        },
    })
    /*c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid)
     */
    var kv map[interface{}]interface{}
    if len(sessiondata) == 0 {
        kv = make(map[interface{}]interface{})
    } else {
        kv, err = session.DecodeGob(sessiondata)
        if err != nil {
            return nil, err
        }
    }
    rs := &SessionStore{c: ds, sid: sid, values: kv}
    return rs, nil
}

// SessionDestroy delete mysql session by sid
func (mp *Provider) SessionDestroy(sid string) error {
    ds := mp.connectInit()
    defer ds.Close()
    c := ds.DB("Employee").C("Sessions")
    c.Remove(bson.M{
        "session_key": sid,
    }) 
    return nil
}

// SessionGC delete expired values in mysql session
func (mp *Provider) SessionGC() {
    ds := mp.connectInit()
    defer ds.Close()
    c := ds.DB("Employee").C("Sessions")
    c.Remove(bson.M{
        "session_expiry": bson.M{
            "$lt": time.Now().Unix() - mp.maxlifetime,
        },
    })
return
}

// SessionAll count values in mysql session
func (mp *Provider) SessionAll() int {
    var total int
    ds := mp.connectInit()
    defer ds.Close()
    c := ds.DB("Employee").C("Sessions")
    total, err := c.Count()

    if err != nil {
        return 0
    }
    return total
}

func init() {
    session.Register("mongodb", mgopder)
}

错误:

panic: runtime error: invalid memory address or nil pointer dereference
        panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x6db254]

goroutine 6 [running]:
panic(0xa2f560, 0xc0820080b0)
        C:/Go/src/runtime/panic.go:481 +0x3f4
gopkg.in/mgo%2ev2.(*Session).Close(0x0)
        C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:1612 +0x144
panic(0xa2f560, 0xc0820080b0)
        C:/Go/src/runtime/panic.go:443 +0x4f7
gopkg.in/mgo%2ev2.(*Session).acquireSocket(0x0, 0xc082290000, 0x0, 0x0, 0x0)
        C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:4409 +0x4ba
gopkg.in/mgo%2ev2.(*Collection).writeOp(0xc082279f30, 0x8feb80, 0xc082326060, 0xc082326001, 0x0, 0x0, 0x0)
        C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:4604 +0xe7
gopkg.in/mgo%2ev2.(*Collection).Remove(0xc082279f30, 0x9d4700, 0xc082326030, 0x0, 0x0)
        C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:2586 +0x15c
sample/models.(*Provider).SessionGC(0xe2f5a0)
        C:/Projects/Go/src/sample/models/model.go:234 +0x3dc
github.com/astaxie/beego/session.(*Manager).GC(0xc082258b20)
        C:/Projects/Go/src/github.com/astaxie/beego/session/session.go:271 +0x48
created by github.com/astaxie/beego.registerSession
        C:/Projects/Go/src/github.com/astaxie/beego/hooks.go:68 +0x31d

最佳答案

这是我通常做的。

package mongo

import (
    "time"

    "gopkg.in/mgo.v2"
)

// DataStore containing a pointer to a mgo session
type DataStore struct {
    Session *mgo.Session
}

// ConnectToTagserver is a helper method that connections to pubgears' tagserver
// database
func (ds *DataStore) ConnectToTagserver() {
    mongoDBDialInfo := &mgo.DialInfo{
        Addrs:    []string{"some IP"},
        Timeout:  60 * time.Second,
        Database: "some db",
    }
    sess, err := mgo.DialWithInfo(mongoDBDialInfo)
    if err != nil {
        panic(err)
    }
    sess.SetMode(mgo.Monotonic, true)
    ds.Session = sess
}

// Close is a helper method that ensures the session is properly terminated
func (ds *DataStore) Close() {
    ds.Session.Close()
}

然后在我的模型包中我做这样的事情

package models

import (
    "./mongo"
    "gopkg.in/mgo.v2/bson"
)

// AdSize represents the data object stucture that is returned by querying
// mongo's account collection
type AdSize struct {
    ID        bson.ObjectId `bson:"_id,omitempty"`
    Providers []string      `bson:"providers"`
    Size      string        `bson:"size"`
}

// GetAllAdsizes is a helper function designed to retrieve all the objects in the
// adsize collection
func GetAllAdsizes() ([]AdSize, error) {
    ds := mongo.DataStore{}
    ds.ConnectToTagserver()
    defer ds.Close()
    adSizes := []AdSize{}
    adSizeCollection := ds.Session.DB("some database").C("some collection")
    err := adSizeCollection.Find(bson.M{}).Sort("name").All(&adSizes)
    return adSizes, err
}

所以我在 mongo 文件中创建了一个 session 包装器,然后在模型文件中创建了一个 session 对象,最后在一些路由文件中我调用了处理我的 mongo session 的方法 GetAllAdsizes()。 session 一直保持事件状态,直到 GetAllAdsizes() 方法结束,因为它在延迟时关闭。但是,可以修改类似这样的内容,您可以在其中处理所有用户内容,然后在用户注销时关闭 session 。也看看这里Best practice to maintain a mgo session ,您可以在其中看到类似类型的逻辑。

关于mongodb - 在 mongodb golang 中保存 session ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39634610/

有关mongodb - 在 mongodb golang 中保存 session的更多相关文章

  1. ruby-on-rails - Rails 优雅地处理超时 session ? - 2

    使用rails4,ruby2。我在rails配置中为我的cookiesession设置了30分钟的超时时间。问题是,如果我转到表单,让session超时,然后提交表单,我会收到此ActionController::InvalidAuthenticityToken错误。如何在Rails中优雅地处理这个错误?比如说,重定向到登录屏幕? 最佳答案 在您的ApplicationController:rescue_fromActionController::InvalidAuthenticityTokendoredirect_tosome_p

  2. ruby-on-rails - 为什么在 Rails 5.1.1 中删除了 session 存储初始化程序 - 2

    我去了这个website查看Rails5.0.0和Rails5.1.1之间的区别为什么5.1.1不再包含:config/initializers/session_store.rb?谢谢 最佳答案 这是删除它的提交:Setupdefaultsessionstoreinternally,nolongerthroughanapplicationinitializer总而言之,新应用没有该初始化器,session存储默认设置为cookie存储。即与在该初始值设定项的生成版本中指定的值相同。 关于

  3. ruby - Sinatra session 未按预期持续 - 2

    我正在尝试使用Sinatra中的重定向和session在网站周围传递一些数据。这是一个简化的示例,使用PrettyPrint进行调试:require'pp'require'rubygems'require'sinatra'enable:sessionsget'/'dosession[:foo]='12345'puts'session1'ppsessionredirectto('/redir')endget'/redir'doputs'session2'ppsession'helloworld'end查看Thin的输出,我看到:>>Listeningon0.0.0.0:4567,CTRL

  4. ruby-on-rails - 如何在 Rails 3 中保存到数据库之前格式化值 - 2

    我有一个带有利润字段的用户模型。利润字段是DECIMAL(11,0)类型。我在表单上有一个屏蔽输入,允许用户输入1,000美元之类的内容。我想格式化该值并从中删除除数字以外的所有内容,这样我将保存1000。这是我到目前为止所拥有的:classUser但它一直在数据库中保存0。看起来它在我的格式化函数之前将其转换为十进制。 最佳答案 试试这个:defprofit=(new_profit)self[:profit]=new_profit.gsub(/[^0-9]/,'')end 关于ruby

  5. ruby - 如何强制 Rack :session + sinatra to read "rack.session" from params instead of cookies - 2

    我正在处理oauth1.0(twitter和flickr)。网站工作在80端口,oauth服务器工作在8080端口算法:向oauth服务器发送ajax请求以检查用户是否有有效的access_token如果用户没有access_token或access_token已过期,则打开授权窗口在oauth服务器的用户session中保存access_token发送分享数据到oauth服务器它使用sinatra+rack:session+rack::session::sequel+sqlite来存储session。它在每个响应中发送Set-Cookie:rack.session=id我正在使用2种

  6. ruby-on-rails - 如何编写 Rails 4 测试以使用 omniauth-google-oauth2 gem 创建 session ? - 2

    我正在尝试为使用omniauth-google-oauth2gem创建session编写测试。我是否需要将env["omniauth.auth"]变量与post:create一起传递?也许当我试图这样做时,我做错了。我得到的错误如下所示...Rake测试错误1)Error:SessionsControllerTest#test_should_get_create:NoMethodError:undefinedmethod`provider'fornil:NilClassapp/models/user.rb:6:in`from_omniauth'app/controllers/sessi

  7. ruby-on-rails - 如何在 Rails 2 中保存上传的文件 - 2

    您好,我在Rails2应用程序中集成了ZohoSheet,我可以从本地打开新的ZohoSheet,但是当我在zoho编辑器中单击保存时,它会将文件发送到我的服务器,这是我的生产日志ProcessingZohoController#indexto#(for*.*.*.*at2015-10-0811:24:08)[POST]Parameters:{"controller"=>"zoho","filename"=>#,"content"=>#,"eventsource"=>#,"format"=>#,"id"=>#,"action"=>"index"}ActionController::In

  8. ruby - session 未创建 : Chrome version must be between - 2

    当使用ruby​​selenium驱动程序驱动chrome时,我得到/home/travis/.rvm/gems/ruby-2.6.2/gems/selenium-webdriver-3.141.5926/lib/selenium/webdriver/remote/response.rb:72:in`assert_ok':sessionnot创建:Chrome版本必须在70和73之间(Selenium::WebDriver::Error::SessionNotCreatedError)如何解决这个问题?降级chrome不是我想做的事。 最佳答案

  9. ruby - 是否有 Rack::Session::Cookie 用法的基本示例? - 2

    我找不到任何使用Rack::Session::Cookie的简单示例,并且希望能够将信息存储在cookie中,并在以后的请求中访问它并让它过期.这些是我能找到的唯一示例:HowdoIset/getsessionvarsinaRackapp?http://rack.rubyforge.org/doc/classes/Rack/Session/Cookie.html这是我得到的:useRack::Session::Cookie,:key=>'rack.session',:domain=>'foo.com',:path=>'/',:expire_after=>2592000,:secret=

  10. ruby-on-rails - rails : How can you access session variables using multiple controllers? - 2

    我在使用session变量时遇到问题。我有两个名为“graduate_students_controller”和“current_students_controller”的Controller。这些Controller中的每一个都控制不同的View文件。我在这两个Controller中使用session变量来存储session信息。问题来了。假设我有两个View文件“reports/current_students_list”、“reports/graduate_students_list”,每个文件都由上述Controller单独控制。现在,如果我尝试从同一浏览器中打开这两个网页并尝

随机推荐