练习
-
模拟实现权限验证中间件
- 有2个路由,/cookie和/home
- /cookie用于设置cookie
- home是访问查看信息的请求
- 在请求home之前,先跑中间件代码,检验是否存在cookie
-
访问home,会显示错误,因为权限校验未通过
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func AuthMiddleWare() gin.HandlerFunc {
return func(ctx *gin.Context) {
// 获取客户端cookie并校验
if cookie, err := ctx.Cookie("aaa"); err == nil {
if cookie == "key" {
ctx.Next()
return
}
}
//返回错误
ctx.JSON(http.StatusUnauthorized, gin.H{"err": "error"})
// 若验证不通过,不再调用后续的函数处理
ctx.Abort()
return
}
}
func main() {
r := gin.Default()
// 服务端给客户端cookie
r.GET("cookie", func(ctx *gin.Context) {
// 设置ccokie
ctx.SetCookie("aaa", "key", 60, "/", "localhost", false, true)
ctx.String(200, "success!")
})
r.GET("home", AuthMiddleWare(), func(ctx *gin.Context) {
ctx.JSON(200, gin.H{"data": "this is an noisy room"})
})
r.Run()
}
cookie缺点
- 不安全,明文
- 增加带宽消耗
- 可以被禁用
- cookie有限
Session
gorilla/sessions为自定义session后端提供cookie和文件系统session以及基础结构。
主要功能是:
- 简单的API:将其用作设置签名(以及可选的加密)cookie的简便方法。
- 内置的后端可将session存储在cookie或文件系统中。
- Flash消息:一直持续读取的session值。
- 切换session持久性(又称“记住我”)和设置其他属性的便捷方法。
- 旋转身份验证和加密密钥的机制。
- 每个请求有多个session,即使使用不同的后端也是如此。
- 自定义session后端的接口和基础结构:可以使用通用API检索并批量保存来自不同商店的session。
package main
import (
"fmt"
"net/http"
"github.com/gorilla/sessions"
)
// 初始化一个cookie存储对象
// something-very-secret应该是一个你自己的密匙,只要不被别人知道就行
var store = sessions.NewCookieStore([]byte("secret"))
func main() {
// 服务端给客户端cookie
http.HandleFunc("/save", SaveSession)
http.HandleFunc("/get", GetSession)
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println("server fail:", err)
return
}
}
func SaveSession(w http.ResponseWriter, r *http.Request) {
// Get a session. We're ignoring the error resulted from decoding an
// existing session: Get() always returns a session, even if empty.
// 获取一个session对象,session-name是session的名字
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 在session中存储值
session.Values["foo"] = "bar"
session.Values[1] = 2
// 保存更改
session.Save(r, w)
}
func GetSession(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
foo := session.Values["foo"]
fmt.Println(foo)
}
func DelSession(w http.ResponseWriter, r *http.Request) {
// 删除session的值
// 将session的最大存储时间设置为小于零的数值即为删除
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
session.Options.MaxAge = -1
session.Save(r, w)
}