• Cookie/Session


    1. Cookie

    • HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出
    • Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思
    • Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求
    • Cookie由服务器创建,并发送给浏览器,最终由浏览器保存

    2. Cookie的用途

    • 保持用户登录状态
    • 京东购物车

    3. cookie的使用

    • 测试服务端发送cookie给客户端,客户端请求时携带cookie
    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"fmt"
    )
    
    func main() {
    	// 创建路由
    	r := gin.Default()
    	// 服务端要给客户端cookie
    	r.GET("cookie", func(c *gin.Context) {
    		// 获取客户端是否携带cookie
    		cookie, err := c.Cookie("key_cookie") //c.Request.Cookie也行
    		if err != nil {
    			cookie = "NotSet"
    			// 给客户端设置cookie
    				// maxAge 单位为秒
    				// path cookie所在目录
    				// domain 域名 
    				// secure 是否智能通过https访问
    				// httpOnly 是否允许别人通过js获取自己的cookie
    			c.SetCookie("key_cookie", "value_cookie", 60, "/",
    				"localhost", false, true)
    		}
    		fmt.Printf("cookie的值是: %s
    ", cookie)
    	})
    	r.Run(":8000")
    }

    3.1 使用

    package main
    
    import (
       "github.com/gin-gonic/gin"
       "net/http"
    )
    
    func AuthMiddleWare() gin.HandlerFunc {
       return func(c *gin.Context) {
          // 获取客户端cookie并校验
          if cookie, err := c.Cookie("abc"); err == nil {
             if cookie == "123" {
                c.Next()
                return
             }
          }
          // 返回错误
          c.JSON(http.StatusUnauthorized, gin.H{"error": "err"})
          // 若验证不通过,不再调用后续的函数处理
          c.Abort()
          return
       }
    }
    
    func main() {
       // 创建路由
       r := gin.Default()
       r.GET("/login", func(c *gin.Context) {
          // 设置cookie
          c.SetCookie("abc", "123", 60, "/",
             "localhost", false, true)
          // 返回信息
          c.String(200, "Login success!")
       })
       r.GET("/home", AuthMiddleWare(), func(c *gin.Context) {
          c.JSON(200, gin.H{"data": "home"})
       })
       r.Run(":8000")
    }
    

    3.2 Cookie的缺点

    • 不安全,明文

    • 增加带宽消耗

    • 可以被禁用

    • cookie有上限

    4. Session

    • Session可以弥补Cookie的不足,Session必须依赖于Cookie才能使用,生成一个SessionId放在Cookie里传给客户端就可以

    4.1 session中间件

    session.go

    package session
    
    type Session interface {
       Set(key string, value interface{}) error
       Get(key string) (interface{}, error)
       Del(key string) error
       Save() error
    }

    session_mgr.go

    package session
    
    // 定义管理者,管理所有session
    type SessionMgr interface {
       // 初始化
       Init(addr string, options ...string) (err error)
       CreateSession() (session Session, err error)
       Get(sessionId string) (session Session, err error)
    }
    

    memory.go

    package session
    
    import (
       "sync"
       "errors"
    )
    
    // 对象
    //    MemorySeesion设计:
    //    定义MemorySeesion对象(字段:sessionId、存kv的map,读写锁)
    //    构造函数,为了获取对象
    //    Set()
    //    Get()
    //    Del()
    //    Save()
    
    type MemorySession struct {
       sessionId string
       // 存kv
       data   map[string]interface{}
       rwlock sync.RWMutex
    }
    
    // 构造函数
    func NewMemorySession(id string) *MemorySession {
       s := &MemorySession{
          sessionId: id,
          data:      make(map[string]interface{}, 16),
       }
       return s
    }
    
    func (m *MemorySession) Set(key string, value interface{}) (err error) {
       // 加锁
       m.rwlock.Lock()
       defer m.rwlock.Unlock()
       // 设置值
       m.data[key] = value
       return
    }
    
    func (m *MemorySession) Get(key string) (value interface{}, err error) {
       m.rwlock.Lock()
       defer m.rwlock.Unlock()
       value, ok := m.data[key]
       if !ok {
          err = errors.New("key not exists in session")
          return
       }
       return
    }
    
    func (m *MemorySession) Del(key string) (err error) {
       m.rwlock.Lock()
       defer m.rwlock.Unlock()
       delete(m.data, key)
       return
    }
    
    func (m *MemorySession) Save(key string) (err error) {
       return
    }
    

    memory_session_mgr.go

    package session
    
    import(
       "sync"
    
       uuid "github.com/satori/go.uuid"
       )
    
    //    MemorySeesionMgr设计:
    //    定义MemorySeesionMgr对象(字段:存放所有session的map,读写锁)
    //    构造函数
    //    Init()
    //    CreateSeesion()
    //    GetSession()
    
    // 定义对象
    type MemorySeesionMgr struct {
       sessionMap map[string]Session
       rwlock     sync.RWMutex
    }
    
    // 构造函数
    func NewMemorySeesionMgr() SessionMgr {
       sr := &MemorySeesionMgr{
          sessionMap: make(map[string]Session, 1024),
       }
       return sr
    }
    
    func (s *MemorySeesionMgr) Init(addr string, options ...string) (err error) {
       return
    }
    
    func (s *MemorySeesionMgr)CreateSession()(session Session,err error)  {
       s.rwlock.Lock()
       defer s.rwlock.Unlock()
       // go get github.com/satori/go.uuid
       // 用uuid作为sessionId
       id, err := uuid.NewV4()
       if err != nil{
          return
       }
       // 转string
       sessionId := id.String()
       // 创建个session
       session = NewMemorySession(sessionId)
    
       return
    }
    
    func (s *MemorySeesionMgr)Get(sessionId string)(session Session,err error)  {
       return
    }
    

      

  • 相关阅读:
    urql 高度可自定义&&多功能的react graphql client
    使用vault pki 为nginx 生成tls 证书文件
    使用vault pki engine 方便的管理证书
    使用terraform 生成自签名证书
    Kapitan 通用terraform&& kubernetes 配置管理工具
    sqler 集成 terraform v0.12 生成资源部署文件
    检查cgroup v2 是否安装
    centos 较新版本kernel安装方法
    tbls ci 友好的数据库文档化工具
    graphql-query-rewriter 无缝处理graphql 变更
  • 原文地址:https://www.cnblogs.com/yzg-14/p/13153459.html
Copyright © 2020-2023  润新知