Beego2已经发布有一段时间了,之前项目都是使用JWT做会话管理,一直没用Session,本次发文记录一下使用的坑。
- 如何安装Beego
go get github.com/beego/beego/v2@v2.0.0
- 如何在项目中引用Beego2?
package main
import "github.com/beego/beego/v2/server/web"
//在Beego2中,默认包名为web,在Beego1中,默认包名为Beego
func main() {
//启动Beego
web.Run()
}
- Beego2的Session模块,传送门:Session模块
开启Session的两种方式:在web.run()启用Session
package main
import "github.com/beego/beego/v2/server/web"
func main() {
//设置Session启用
web.BConfig.WebConfig.Session.SessionOn = true
//启动Beego
web.Run()
}
第二种方式:通过配置文件修改
//启用Session sessionon=true //设置Session别名,这里影响Set-Cookie是key的名字替换为SessionName SessionName="SessionName"
由于Chrome的安全策略限制,使用Beego2的Session中,初次登入调用Set-Cookie时,Chrome无法将用户凭据保存在本地Cookie中,原因是Chrome默认将SameSite设置为Lax,导致跨域时无法携带和保存Cookie。
解决方法可以手动设置Cookie,并设置SameSite属性,并在前端框架中配置允许用户使用Https访问页面。
实例代码如下:
package controllers
import (
"context"
"net/http"
)
//获取生成Session的ID
sid := c.CruSession.SessionID(context.Background())
http.SetCookie(c.Ctx.ResponseWriter, &http.Cookie{
Name: "SessionNmae",
Value: sid,
Path: "/",
//为Cookie设置Secure属性
Secure: true,
//设置HttpOnly属性为True,那么通过JS脚本将无法读取到cookie信息
HttpOnly: true,
//显示设置SameSite为None
SameSite: http.SameSiteNoneMode,
//设置Cookie过期时间
Expires: time.Now().Add(8 * time.Hour),
})
设置完成后在调用Login接口,你会发现Chrome中的Cookie可以正常保存到本地了。
方案2:- 当在Config文件中Session = on时,使用默认配置会导致Beego2进行AutoSetCookie
// 文件路径 : /beego/server/web/config.go
func newBConfig() *Config {
res := &Config{
..... //省略一部分代码
WebConfig: WebConfig{
....
Session: SessionConfig{
SessionOn: false,
SessionProvider: "memory",
SessionName: "beegosessionID",
SessionGCMaxLifetime: 3600,
SessionProviderConfig: "",
SessionDisableHTTPOnly: false,
SessionCookieLifeTime: 0,
// set cookie default is the browser life
//重点在这里,AutoSetCookie会自动给没有Cookie的请求返回一个新的Cookie,Cookie=SessionID
SessionAutoSetCookie: true,
SessionDomain: "",
SessionEnableSidInHTTPHeader: false,
SessionNameInHTTPHeader: "Beegosessionid",
SessionEnableSidInURLQuery: false,
SessionCookieSameSite: http.SameSiteDefaultMode,
},
},
...... //省略一部分代码
}
res.RecoverFunc = defaultRecoverPanic
return res
}
- 关闭AutoSetCookie,只需要在Config文件中设置
SessionAutoSetCookie = false
- 之前我们是这么处理的
sid := c.CruSession.SessionID(context.Background())
http.SetCookie(c.Ctx.ResponseWriter, &http.Cookie{
Name: "SID",
Value: sid,
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteNoneMode,
Expires: time.Now().Add(8 * time.Hour),
})
- 这样有个缺点,就是Header会产生两个Set-Cookie字段,可以使用以下方案避免
func (c *AccountController) Login() {
if (登录验证通过){
doFunctionB();
}else {
doFunctionA();
}
//一个参数Cookie名字,第二个参数Cookie值,第三个参数是不定值,分别用来设置Path, Domain【Domain必须为空,否则无法SetCookie无法保存到本地】, Secure, HttpOnly,SameSite
c.Ctx.Output.Cookie("SID", sid, 8*time.Hour, "/", "", true, true,"None")
}
- Beego2调用AutoSetCookie底层调用的设置Cookie的源码,可供读者参考,在BeegoV2.0.2新增SameSite字段,V2.0.1及以下版本无法设置SameSite
func (output *BeegoOutput) Cookie(name string, value string, others ...interface{}) {
var b bytes.Buffer
fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value))
// fix cookie not work in IE
if len(others) > 0 {
var maxAge int64
switch v := others[0].(type) {
case int:
maxAge = int64(v)
case int32:
maxAge = int64(v)
case int64:
maxAge = v
}
switch {
case maxAge > 0:
fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge)
case maxAge < 0:
fmt.Fprintf(&b, "; Max-Age=0")
}
}
// the settings below
// Path, Domain, Secure, HttpOnly
// can use nil skip set
// default "/"
tmpPath := "/"
if len(others) > 1 {
if v, ok := others[1].(string); ok && len(v) > 0 {
tmpPath = sanitizeValue(v)
}
}
fmt.Fprintf(&b, "; Path=%s", tmpPath)
// default empty
if len(others) > 2 {
if v, ok := others[2].(string); ok && len(v) > 0 {
fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(v))
}
}
// default empty
if len(others) > 3 {
var secure bool
switch v := others[3].(type) {
case bool:
secure = v
default:
if others[3] != nil {
secure = true
}
}
if secure {
fmt.Fprintf(&b, "; Secure")
}
}
// default false. for session cookie default true
if len(others) > 4 {
if v, ok := others[4].(bool); ok && v {
fmt.Fprintf(&b, "; HttpOnly")
}
}
// default empty
if len(others) > 5 {
if v, ok := others[5].(string); ok && len(v) > 0 {
fmt.Fprintf(&b, "; SameSite=%s", sanitizeValue(v))
}
}
output.Context.ResponseWriter.Header().Add("Set-Cookie", b.String())
}
可以看到Cookie的设置成功了,Chrome也不会出现SameSite的Warning



