1. Sessions

当你使用一个应用程序,你打开它,做了一些改变,然后关闭它。这就像一个会话。计算机知道你是谁。它知道你什么时候开始这个程序,什么什么时候关闭。但是在互联网上,这是一个问题:web服务器不知道你是谁,也不知道你做什么,因为HTTP不能保持状态。

Session 变量通过存储要在多个页面上使用的用户信息(例如用户名,喜欢的颜色等)来解决此问题。默认情况下,Session 变量会一直存在,直到浏览器关闭。

因此,Session 变量保存有关一个用户的信息,并且可用于一个应用程序中的所有页面。

Tip:如果你想要持久化存储,你可以存储数据到数据库中。

Iris 在 iris/sessions 子包中有自己的会话实现和会话管理。你只需导入这个包就能使用了。

一个会话通过 Session 对象的 Start 函数开始,Session 对象是通过 New 函数创建的,这个函数会返回一个 Sessoin

Session 变量通过 Session.Set 方法设置,通过 Session.Get 方法取回。使用 Session.Delete 删除一个变量。要删除整个会话并使之无效,请使用 Session.Destroy 方法。

session 管理器通过 New 方法创建的。

import "github.com/kataras/iris/v12/sessions
sess := sessions.New(sessions.Config{Cookie: "cookieName", ...})

Config

Config struct {
        // session 的 cookie名字,例如:"mysessionid"
        // 默认为 "irissessionid"
        Cookie string

        // 如果服务器通过 TLS 运行,CookieSecureTLS 设置为true,
        // 你需要把 session的cookie的 "Secure" 字段设置为 true。
        //
        // 记住:为了正常工作用户应该指定"Decode" 配置字段。
        // 建议:您不需要将此字段设置为true,只需在_examples文件夹中提供
        // example的第三方库(例如secure cookie)填充Encode和Decode字段即可。
        // 
        // 默认为 false
        CookieSecureTLS bool

        // AllowReclaim 将允许在想用的请求处理器中清除然后重新开始一个session
        // 它所做的只是在“Destroy”时删除“Request”和“ ResponseWriter”的cookie,
        // 或者在“Start”时将新cookie添加到“请求”。
        //
        // 默认为 false
        AllowReclaim bool

        // 当cookie值不为nil时编码此cookie值(config.Cookie字段指定的值)。
        // 接受cookie的名字为第一个参数,第二个参数为服务器产生的session id。
        // 返回新的session id,如果发生错误,session id将置为空,这是无效的。
        // 
        // 提示:错误将不会打印,因此你应该清楚你所做的。
        // 记住:如果你使用 AES,它仅支持key的大小为16,24,或者32 bytes。
        // 你要么提供准确的值或者从你键入的内容中得到key
        // 
        // 默认为nil
        Encode func(cookieName string, value interface{}) (string, error)

        // 如果cookie值不为nil则对其解码
        // 第一个参数为cookie的名字(config.Cookie字段指定的值),
        // 第二个参数为客户端的cookie值(也就是被编码后的 session id),
        // 当操作失败时返回错误
        //
        // 提示:错误将不会打印,因此你应该清楚你所做的。
        // 记住:如果你使用 AES,它仅支持key的大小为16,24,或者32 bytes。=
        // 你要么提供准确的值或者从你键入的内容中得到key
        // 
        // 默认为nil
        Decode func(cookieName string, cookieValue string, v interface{}) error

        // Defaults to nil.
        // Encoding 功能与 Encode和Decode类似,但是接受一个实例,
        // 这个实例实现了 "CookieEncoder" 接口(Encode和Decode方法)。
        //
        // 默认为nil
        Encoding Encoding

        // 指定cookie必须的生存时间(created_time.Add(Expires)),
        // 如果你想要在浏览器关闭时删除cookie,就设置为 -1。
        //  0 意味着没有过期时间(24年),
        // -1 意味着浏览器关闭时删除
        // >0 就是指定session 的cookie生存期(time.Duration类型)。 
        Expires time.Duration

        // SessionIDGenerator 可以设置一个函数,用于返回一个唯一的session id。
        // 默认将使用uuid包来生成session id,但是开发者可以通过指定这个字段来改变这个行为。
        SessionIDGenerator func(ctx context.Context) string

        // DisableSubdomainPersistence 设置为true时,
        // 将不允许你的子域名拥有访问session 的cookie的权利
        //
        // 默认为false
        DisableSubdomainPersistence bool
    }

New 返回一个 Sessions 的指针,并拥有这些方法:

// 为特定的请求创建或者取回一个已经存在的session。
Start(ctx iris.Context, cookieOptions ...iris.CookieOption)

// Handler 返回一个session中间件,用以注册到应用程序路由中。
Handler(cookieOptions ...iris.CookieOption) iris.Handler    

// 移除session数据和相关cookie。
Destroy(ctx context.Context)

// 移除服务器端内存(和已注册的数据库)中的所有session。
// 客户端的session cookie将依然存在,但是它将会被下个请求重新设置
DestroyAll()

// DestroyByID 移除服务器端内存(和已注册的数据库)中的session 条目。
// 客户端的session cookie将依然存在,但是它将会被下个请求重新设置
// 使用这个很安全,即使你不确定这个id对应的session是否存在。
// 提示:sid应该是原始的数据(即从存储中获取),不是已经解码的。
DestroyByID(sessID string)

// OnDestroy 注册一个或者多个移除监听者。
// 当一个服务端或者客户端(cookie)的session被移除,将会触发监听者。
// 记住如果一个监听者被阻塞,会话管理器将都会延迟,
// 在侦听器中使用goroutine避免这种情况。
OnDestroy(callback func(sid string))

// ShiftExpiration 通过session默认的超时配置,将会话的过期日期更改到新的日期
// 如果使用数据库保存session将会抛出 "ErrNotImplemented" 错误,因为数据库不支持这个特性。
ShiftExpiration(ctx iris.Context,
         cookieOptions ...iris.CookieOption) error

// UpdateExpiration 通过 "expires" 这个超时值将session的超时日期改为新的日期。
// 如果更新一个不存在或者无效的session条目,将会返回 "ErrNotFound" 异常。
//  如果使用数据库保存session将会抛出 "ErrNotImplemented" 错误,因为数据库不支持这个特性。
UpdateExpiration(ctx iris.Context, expires time.Duration,
         cookieOptions ...iris.CookieOption) error

// UseDatabase 添加一个session数据库到session管理器中,
// 会话数据库没有写访问权
UseDatabase(db Database)

这里的 CookieOption 仅仅是一个 func(*http.Cookie) 函数,允许自定义配置cookie的属性。

Start 方法返回一个 Session 指针值,这个指针有自己的方法来为每个session工作。

func (ctx iris.Context) {
    session := sess.Start(ctx)

        // 返回session的id
        .ID() string

        // 如果这个session是在当前处理流程中创建,将返回true
        .IsNew() bool

        //  根据会话的键,填充相应的值
         .Set(key string, value interface{})

        // 根据会话的键,填充相应的值。
        // 与 Set 不同,当使用 Get 时,无法改变输出值
        //  一个不可变的条目只能通过 SetImmutable 改变,Set将不能工作
        // 如果条目是不可变的,这将是安全的。         
        // 谨慎使用,它比 Set 慢
        .SetImmutable(key string, value interface{})

        // 获取所有值的一个备份
        .GetAll() map[string]interface{}

        // 返回这个session保存的值的总数
        .Len() int

        // 移除key对应的条目,如果有条目移除则返回true
        .Delete(key string) bool

        // 移除所有的session条目
        .Clear()

        // 返回key对应的值
        .Get(key string) interface{}

        // 与Get类似,但是返回的是值的字符串表示形式。
        // 如果不存在key,返回空字符串。
        .GetString(key string) string

        // 与Get类似,但是返回的是值的字符串表示形式。
        // 如果不存在key,返回defaultValue定义的默认值。
        .GetStringDefault(key string, defaultValue string) string

        // 与Get类似,但是返回的是值的int表示形式。
        // 如果不存在key,返回-1和一个非nil的错误
        .GetInt(key string) (int, error)

        // 与Get类似,但是返回的是值的int表示形式。
        // 如果不存在key,返回defaultValue定义的默认值。
        .GetIntDefault(key string, defaultValue int) int

        // 将保存的key的值+n,
        // 如果key不存在,则设置key的值为n
        // 返回增加后的值
        .Increment(key string, n int) (newValue int)

        // 将保存的key的值-n,
        // 如果key不存在,则设置key的值为n
        // 返回减少后的值
        .Decrement(key string, n int) (newValue int)

        // 与Get类似,但是返回的是值的int64表示形式。
        // 如果不存在key,返回-1和一个非nil的错误
        .GetInt64(key string) (int64, error)

        // 与Get类似,但是返回的是值的int64表示形式。
        // 如果不存在key,返回defaultValue定义的默认值。
        .GetInt64Default(key string, defaultValue int64) int64

        // 与Get类似,但是返回的是值的float32表示形式。
        // 如果不存在key,返回-1和一个非nil的错误
        .GetFloat32(key string) (float32, error)

        // 与Get类似,但是返回的是值的float32表示形式。
        // 如果不存在key,返回defaultValue定义的默认值。
        .GetFloat32Default(key string, defaultValue float32) float32

        // 与Get类似,但是返回的是值的float64表示形式。
        // 如果不存在key,返回-1和一个非nil的错误
        .GetFloat64(key string) (float64, error)

        // 与Get类似,但是返回的是值的float64表示形式。
        // 如果不存在key,返回defaultValue定义的默认值。
        .GetFloat64Default(key string, defaultValue float64) float64

        // 与Get类似,但是返回的是值的boolean表示形式。
        // 如果不存在key,返回-1和一个非nil的错误
        .GetBoolean(key string) (bool, error)

        // 与Get类似,但是返回的是值的boolean表示形式。
        // 如果不存在key,返回defaultValue定义的默认值。
        .GetBooleanDefault(key string, defaultValue bool) bool

        // 通过key设置一个即时信息。
        // 即时信息是为了保存一个信息到session中,这样同一个用户的多个请求都能获取到这个信息。
        // 当这个信息展示给用户后就会被移除。
        // 即时信息通常用于与HTTP重定向组合,
        // 因为这种情况下是没有视图的,信息只能在重定向后展示给用户。
        // 
        // 一条即时信息拥有它的key和内容。
        // 这是一个有关联的数组。
        // 名字是一个字符串:通常为"notice","sucess","error",但是可以为任何string。
        // 内容通常是stirng。如果你想直接显示它,你可以放一些HTML标签在信息中。
        // 也可以放置一个数组或者数组:将会被序列化,然后以字符串类型保存。
        // 
        // 即时信息可以是用哪个 SetFlash 方法设置。
        // 例如,你想要通知用户他的改变成功保存了,
        // 你可以在你的处理中添加下面一行:SetFlash("success", "data saved")
        // 在这个例子中我们使用key"success",如果你想要定义更多即时信息,你可以使用不同的key。
        .SetFlash(key string, value interface{})

        // 如果这个session有可用的即时信息将返回true
        .HasFlash() bool

        // GetFlashes 返回所有的即时信息的值,使用的是 map[string]interface{} 格式。
        // 记住:这将导致在同一用户的下一个请求上删除所有当前的即时消息。
         .GetFlashes() map[string]interface{}
        // PeekFlash 返回key对应的暂存的即时信息。
        // 与GetFlash不同,这个信息在下个请求时可用,除非使用GetFlashes或者GetFlash
        .PeekFlash(key string) interface{}

        // GetFlash返回key对应的存储的即时信息,并且在下个请求中移除这个即时信息。
        // 检查即时信息我们使用 HashFlash() 方法,获得即时信息我们使用GetFlash()方法。
        // GetFlashes() 获取所有的信息。
        // 获取信息并从session删除,这意味着一条消息只能在提供给用户的第一个页面上显示。
        .GetFlash(key string) interface{}

        // 与GetFlash类似,但是返回的是string表示形式,
        // 如果key不存在,则返回空string
        .GetFlashString(key string) string

        // 与GetFlash类似,但是返回的是string表示形式,
        // 如果key不存在,则返回defaultValue指定的默认值
        .GetFlashStringDefault(key string, defaultValue string) string

        // 删除key这个即时信息
        .DeleteFlash(key string)

        // 移除所有的即时信息
        .ClearFlashes()

        // "摧毁"这个session,它移除session的值和所有即时信息。
        // session条目将会从服务器中移除,注册的session数据库也会被通知删除。
        // 记住这个方法不会移除客户端的cookie,如果附上新的session客户端的cookie将会被重置。
        // 使用会话管理器的 "Destroy(ctx)" 来移除cookie。
        .Destroy()
}

1.1.1. 示例:

在这里例子中我们将允许通过验证的用户访问 /secret 的隐秘信息。为了有访问的权限,我们首先需要访问 /login 来获取一个可用的session 的 cookie,使它登录成功。另外也可以访问 /logout 撤销访问权限。

// sessions.go
package main

import (
    "github.com/kataras/iris/v12"

    "github.com/kataras/iris/v12/sessions"
)

var (
    cookieNameForSessionID = "mycookiesessionnameid"
    sess                   = sessions.New(sessions.Config{Cookie: cookieNameForSessionID})
)

func secret(ctx iris.Context) {
    // Check if user is authenticated
    if auth, _ := sess.Start(ctx).GetBoolean("authenticated"); !auth {
        ctx.StatusCode(iris.StatusForbidden)
        return
    }

    // Print secret message
    ctx.WriteString("The cake is a lie!")
}

func login(ctx iris.Context) {
    session := sess.Start(ctx)

    // Authentication goes here
    // ...

    // Set user as authenticated
    session.Set("authenticated", true)
}

func logout(ctx iris.Context) {
    session := sess.Start(ctx)

    // Revoke users authentication
    session.Set("authenticated", false)
    // Or to remove the variable:
    session.Delete("authenticated")
    // Or destroy the whole session:
    session.Destroy()
}

func main() {
    app := iris.New()

    app.Get("/secret", secret)
    app.Get("/login", login)
    app.Get("/logout", logout)

    app.Run(iris.Addr(":8080"))
}

访问:

$ go run sessions.go

$ curl -s http://localhost:8080/secret
Forbidden

$ curl -s -I http://localhost:8080/login
Set-Cookie: mysessionid=MTQ4NzE5Mz...

$ curl -s --cookie "mysessionid=MTQ4NzE5Mz..." http://localhost:8080/secret
The cake is a lie!

results matching ""

    No results matching ""