gosession

package module
v1.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2021 License: Apache-2.0 Imports: 9 Imported by: 1

README

Distributed Session Implement By Golang

GitHub forks GitHub stars GitHub last commit Go Report Card GitHub issues

中文说明

Support multi web service share session token, which can keep union state in many diff service.

Now session token can store in:

  1. Single mode Redis.
  2. Sentinel mode Redis.

Usage

simple get it by:

go get -v github.com/hunterhug/gosession

core api:

// token manage
// token will be put in cache database such redis and user info relate with that token will cache too
type TokenManage interface {
	SetToken(id string, tokenValidTimes int64) (token string, err error)                               // Set token, expire after some second
	RefreshToken(token string, tokenValidTimes int64) error                                            // Refresh token,token expire will be again after some second
	DeleteToken(token string) error                                                                    // Delete token when you do action such logout
	CheckToken(token string) (user *User, exist bool, err error)                                       // Check the token,  but not refresh user info cache
	CheckTokenOrUpdateUser(token string, userInfoValidTimes int64) (user *User, exist bool, err error) // Check the token, when cache database exist return user info directly, others hit the persistent database and save newest user in cache database then return. such redis check, not check load from mysql.
	ListUserToken(id string) ([]string, error)                                                         // List all token of one user
	DeleteUserToken(id string) error                                                                   // Delete all token of this user
	RefreshUser(id []string, userInfoValidTimes int64) error                                           // Refresh cache of user info batch
	DeleteUser(id string) error                                                                        // Delete user info in cache
	AddUser(id string, userInfoValidTimes int64) (user *User, exist bool, err error)                   // Add the user info to cache,expire after some second
	ConfigTokenKeyPrefix(tokenKey string) TokenManage                                                  // Config chain, just cache key prefix
	ConfigUserKeyPrefix(userKey string) TokenManage                                                    // Config chain, just cache key prefix
	ConfigExpireTime(second int64) TokenManage                                                         // Config chain, token expire after second
	ConfigGetUserInfoFunc(fn GetUserInfoFunc) TokenManage                                              // Config chain, when cache not found user info, will load from this func
	SetSingleMode() TokenManage                                                                        // Can set single mode, before one new token gen, will destroy other token
}

// core user info, it's Id will be the primary key store in cache database such redis
type User struct {
	Id                  string      `json:"id"`     // unique mark
	TokenRemainLiveTime int64       `json:"-"`      // token remain live time in cache
	Detail              interface{} `json:"detail"` // can diy your real user info by config ConfigGetUserInfoFunc()
}

one simple example:

package main

import (
	"fmt"
	"github.com/hunterhug/gosession"
)

func main() {
	tokenManage, err := gosession.NewRedisSessionSimple("127.0.0.1:6379", 0, "hunterhug")
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	userId := "000001"
	token, err := tokenManage.SetToken(userId, 20)
	if err != nil {
		fmt.Println("set token err:", err.Error())
		return
	}
	fmt.Println("set token:", userId, token)

	user, exist, err := tokenManage.CheckToken(token)
	if err != nil {
		fmt.Println("check token err:", err.Error())
		return
	}

	if exist {
		fmt.Printf("check token exist: %#v\n", user)
	} else {
		fmt.Println("check token not exist")
	}

	err = tokenManage.DeleteToken(token)
	if err != nil {
		fmt.Println("delete token err:", err.Error())
		return
	} else {
		fmt.Println("delete token:", token)
	}

	user, exist, err = tokenManage.CheckToken(token)
	if err != nil {
		fmt.Println("after delete check token err:", err.Error())
		return
	}

	if exist {
		fmt.Printf("after delete check delete token exist: %#v\n", user)
	} else {
		fmt.Println("after delete check delete token not exist")
	}

	tokenManage.SetToken(userId, 20)
	tokenManage.SetToken(userId, 20)
	tokenManage.SetToken(userId, 20)
	tokenManage.SetToken(userId, 20)

	tokenList, err := tokenManage.ListUserToken(userId)
	if err != nil {
		fmt.Println("list token err:", err.Error())
		return
	}

	for _, v := range tokenList {
		fmt.Println("list token:", v)
	}

	err = tokenManage.DeleteUserToken(userId)
	if err != nil {
		fmt.Println("delete user all token err:", err.Error())
		return
	} else {
		fmt.Println("delete user all token")
	}

	tokenList, err = tokenManage.ListUserToken(userId)
	if err != nil {
		fmt.Println("after delete user all list token err:", err.Error())
		return
	}

	if len(tokenList) == 0 {
		fmt.Println("user token empty")
	}
}

another example:

package main

import (
	"fmt"
	"github.com/hunterhug/gosession"
	"time"
)

func main() {
	// 1. config redis
	redisHost := "127.0.0.1:6379"
	redisDb := 0
	redisPass := "hunterhug" // may redis has password
	redisConfig := gosession.NewRedisSessionSingleModeConfig(redisHost, redisDb, redisPass)
	// or
	//gosession.NewRedisSessionSentinelModeConfig(":26379,:26380,:26381",0,"mymaster")

	// 2. connect redis session
	tokenManage, err := gosession.NewRedisSession(redisConfig)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// 3. config token manage
	tokenManage.ConfigDefaultExpireTime(600)
	tokenManage.ConfigUserKeyPrefix("go-user")
	tokenManage.ConfigTokenKeyPrefix("go-token")
	fn := func(id string) (user *gosession.User, err error) {
		return &gosession.User{
			Id:     id,
			Detail: map[string]string{"detail": id},
		}, nil
	} // get user func diy, you can set it nil
	tokenManage.ConfigGetUserInfoFunc(fn)
	//tokenManage.SetSingleMode()

	// 4. set token
	id := "000001"
	var tokenExpireTimeAlone int64 = 2

	token, err := tokenManage.SetToken(id, tokenExpireTimeAlone)
	if err != nil {
		fmt.Println("set token err:", err.Error())
		return
	}

	fmt.Println("token:", token)

	// can set a lot token
	tokenManage.SetToken(id, 100)
	tokenManage.SetToken(id, 100)
	tokenManage.SetToken(id, 100)

	// 5. list all token
	tokenList, err := tokenManage.ListUserToken(id)
	if err != nil {
		fmt.Println("list token err:", err.Error())
		return
	}
	fmt.Println("list token:", tokenList)

	// 6. check token
	var userExpireTimeAlone int64 = 10 // if ConfigGetUserInfoFunc!=nil, will load user info from func if not exist in redis cache
	u, exist, err := tokenManage.CheckTokenOrUpdateUser(token, userExpireTimeAlone)
	if err != nil {
		fmt.Println("check token err:", err.Error())
		return
	}

	fmt.Printf("check token:%#v, %#v,%#v\n", token, u, exist)

	err = tokenManage.RefreshToken(token, 5)
	if err != nil {
		fmt.Println("refresh token err:", err.Error())
		return
	}

	u, exist, err = tokenManage.CheckTokenOrUpdateUser(token, userExpireTimeAlone)
	if err != nil {
		fmt.Println("after refresh check token err:", err.Error())
		return
	}

	fmt.Printf("after refresh token:%#v, %#v,%#v\n", token, u, exist)

	// 7. sleep to see token is exist?
	time.Sleep(10 * time.Second)
	u, exist, err = tokenManage.CheckTokenOrUpdateUser(token, userExpireTimeAlone)
	if err != nil {
		fmt.Println("sleep check token err:", err.Error())
		return
	}

	fmt.Printf("sleep check token:%#v, %#v,%#v\n", token, u, exist)

	// you can delete all token of one user
	tokenList, err = tokenManage.ListUserToken(id)
	if err != nil {
		fmt.Println("sleep list token err:", err.Error())
		return
	}
	fmt.Println("sleep token:", tokenList)

	err = tokenManage.DeleteUserToken(id)
	if err != nil {
		fmt.Println("delete user token err:", err.Error())
		return
	}

	tokenList, err = tokenManage.ListUserToken(id)
	if err != nil {
		fmt.Println("after delete user token list err:", err.Error())
		return
	}
	fmt.Println("after delete user token list:", tokenList)
}

TODO

  1. Support JWT token, that will enable token verify in client side to find the token expire early, also we can filter in server side.
  2. Support Other Db such MySQL or Mongo.
  3. Support Feature of multiple clients single sign on.

License

Copyright [2019-2021] [github.com/hunterhug]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Documentation

Index

Constants

View Source
const (
	// JwtPayloadClientVersionName Todo client jwtPayload version field
	JwtPayloadClientVersionName = "clientVersion"
	// JwtPayloadClientVersion client jwtPayload version value
	JwtPayloadClientVersion = 1.0
)

Variables

View Source
var (

	// TokenMapKeyExpireTime list all token, hash key expire
	TokenMapKeyExpireTime int64 = 3600 * 24 * 30
)

Functions

func GetGUID

func GetGUID() (valueGUID string)

GetGUID gen random uuid

func NewRedisSessionSentinelModeConfig

func NewRedisSessionSentinelModeConfig(redisHost string, redisDB int, redisPass string, masterName string) *kv.MyRedisConf

NewRedisSessionSentinelModeConfig redis sentinel mode config redisHost is sentinel address, not redis address redisPass is redis password

func NewRedisSessionSingleModeConfig

func NewRedisSessionSingleModeConfig(redisHost string, redisDB int, redisPass string) *kv.MyRedisConf

NewRedisSessionSingleModeConfig redis single mode config

func SI

func SI(s string) (i int64)

Types

type GetUserInfoFunc

type GetUserInfoFunc func(id string) (*User, error)

GetUserInfoFunc func get user info from where

var (
	// GetUserInfoFuncDefault default get user info func you can choose
	GetUserInfoFuncDefault GetUserInfoFunc = func(id string) (*User, error) { return &User{Id: id}, nil }
)

type JwtData added in v1.0.13

type JwtData struct {
	// 用户ID
	UserId string `json:"user_id,omitempty"`
	// 创建时间,毫秒
	CreateMSTime int64 `json:"create_ms_time,omitempty"`
	// 辅助
	CreateString string `json:"create_string,omitempty"`
	// 过期时间,毫秒
	ExpiryMSTime int64 `json:"expiry_ms_time,omitempty"`
	// 辅助
	ExpiryString string `json:"expiry_string,omitempty"`
	// 是否已过期
	IsExpire bool `json:"is_expire,omitempty"`
	// 服务端数据库令牌对ID,可忽视
	ServerTokenHandle string `json:"server_token_handle,omitempty"`
	// 客户端Payload数据,返回给客户端的数据,客户端解密可看
	ClientPayload map[string]interface{} `json:"client_payload,omitempty"`
	// 服务端Session数据,保存在服务器端的数据,客户端不可看
	ServerSessionData map[string]interface{} `json:"server_session_data,omitempty"`
}

JwtData 数据

type JwtManage added in v1.0.13

type JwtManage interface {
	// Config 配置令牌有效时间
	Config(refreshTokenExpireTime time.Duration, accessTokenExpireTime time.Duration)
	// CreateNewLogInToken 创建令牌对,可传入客户端或服务端数据
	CreateNewLogInToken(userId string, clientJwtPayload map[string]interface{}, serverSessionData map[string]interface{}) (accessToken, refreshToken string, err error)
	// GetSessionInfoByAccessToken 获取某令牌对信息,先走JWT无状态解码数据,force则强制查询服务端
	GetSessionInfoByAccessToken(accessToken string, force bool) (jwtData JwtData, err error)
	// GetAllSessionsForUser 获取某用户所有令牌对信息
	GetAllSessionsForUser(userId string) (jwtDataList []JwtData, err error)
	// RevokeLogInTokenByUserId 撤销某用户所有令牌对
	RevokeLogInTokenByUserId(userId string) error
	// RevokeLogInTokenByAccessToken 撤销用户某令牌对
	RevokeLogInTokenByAccessToken(accessToken string) (revoke bool, err error)
	// RefreshLogInToken 刷新令牌对
	RefreshLogInToken(refreshToken string) (newAccessToken string, newRefreshToken string, err error)
	// GetSignPublicKey 获取服务端签名key,客户端使用这个来进行解密,可以是空
	GetSignPublicKey() (publicKey string, err error)
	// ParseAccessToken 解析和验证JWT信息,客户端方法
	ParseAccessToken(accessToken string, publicKey string) (jwtData JwtData, err error)
}

JwtManage Todo 另外一种实现的 Session

type RedisSession

type RedisSession struct {
	// contains filtered or unexported fields
}

RedisSession session by redis

func (*RedisSession) AddUser

func (s *RedisSession) AddUser(userId string, userInfoValidTimes int64) (user *User, exist bool, err error)

AddUser Add the user info to cache,expire after some second

func (*RedisSession) CheckToken

func (s *RedisSession) CheckToken(token string) (user *User, exist bool, err error)

func (*RedisSession) CheckTokenOrUpdateUser

func (s *RedisSession) CheckTokenOrUpdateUser(token string, userInfoValidTimes int64) (user *User, exist bool, err error)

CheckTokenOrUpdateUser Check the token, when cache database exist return user info directly, others hit the persistent database and save newest user in cache database then return. such redis check, not check load from mysql. you can check user info by that token, if s.getUserFunc == nil do nothing

func (*RedisSession) ConfigDefaultExpireTime

func (s *RedisSession) ConfigDefaultExpireTime(second int64) TokenManage

ConfigDefaultExpireTime config by chain

func (*RedisSession) ConfigGetUserInfoFunc

func (s *RedisSession) ConfigGetUserInfoFunc(fn GetUserInfoFunc) TokenManage

ConfigGetUserInfoFunc config by chain

func (*RedisSession) ConfigTokenKeyPrefix

func (s *RedisSession) ConfigTokenKeyPrefix(tokenKey string) TokenManage

ConfigTokenKeyPrefix config by chain

func (*RedisSession) ConfigUserKeyPrefix

func (s *RedisSession) ConfigUserKeyPrefix(userKey string) TokenManage

ConfigUserKeyPrefix config by chain

func (*RedisSession) DeleteToken

func (s *RedisSession) DeleteToken(token string) (err error)

DeleteToken Delete token when you do action such logout

func (*RedisSession) DeleteUser

func (s *RedisSession) DeleteUser(userId string) (err error)

DeleteUser Delete user info in cache

func (*RedisSession) DeleteUserToken

func (s *RedisSession) DeleteUserToken(userId string) (err error)

DeleteUserToken Delete all token of this user

func (*RedisSession) ListUserToken

func (s *RedisSession) ListUserToken(userId string) ([]string, error)

ListUserToken List all token in one user

func (*RedisSession) RefreshToken

func (s *RedisSession) RefreshToken(token string, tokenValidTimes int64) (err error)

RefreshToken Refresh token,token expire will be again after some second

func (*RedisSession) RefreshUser

func (s *RedisSession) RefreshUser(ids []string, userInfoValidTimes int64) (err error)

RefreshUser Refresh cache of user info batch

func (*RedisSession) SetSingleMode

func (s *RedisSession) SetSingleMode() TokenManage

SetSingleMode set single mode, new token will destroy other token

func (*RedisSession) SetToken

func (s *RedisSession) SetToken(useId string, tokenValidTimes int64) (token string, err error)

SetToken Set token, expire after some second

type TokenManage

type TokenManage interface {
	SetToken(userId string, tokenValidTimes int64) (token string, err error)                           // Set token, expire after some second
	RefreshToken(token string, tokenValidTimes int64) error                                            // Refresh token,token expire will be again after some second
	DeleteToken(token string) error                                                                    // Delete token when you do action such logout
	CheckToken(token string) (user *User, exist bool, err error)                                       // Check the token,  but not refresh user info cache
	CheckTokenOrUpdateUser(token string, userInfoValidTimes int64) (user *User, exist bool, err error) // Check the token, when cache database exist return user info directly, others hit the persistent database and save newest user in cache database then return. such redis check, not check load from mysql.
	ListUserToken(userId string) ([]string, error)                                                     // List all token of one user
	DeleteUserToken(userId string) error                                                               // Delete all token of this user
	RefreshUser(userId []string, userInfoValidTimes int64) error                                       // Refresh cache of user info batch
	DeleteUser(userId string) error                                                                    // Delete user info in cache
	AddUser(userId string, userInfoValidTimes int64) (user *User, exist bool, err error)               // Add the user info to cache,expire after some second
	ConfigTokenKeyPrefix(tokenKey string) TokenManage                                                  // Config chain, just cache key prefix
	ConfigUserKeyPrefix(userKey string) TokenManage                                                    // Config chain, just cache key prefix
	ConfigDefaultExpireTime(second int64) TokenManage                                                  // Config chain, token expire after second
	ConfigGetUserInfoFunc(fn GetUserInfoFunc) TokenManage                                              // Config chain, when cache not found user info, will load from this func
	SetSingleMode() TokenManage                                                                        // Can set single mode, before one new token gen, will destroy other token
}

TokenManage token manage token will be put in cache database such redis and user info relate with that token will cache too

func NewRedisSession

func NewRedisSession(redisConf *kv.MyRedisConf) (TokenManage, error)

NewRedisSession new a redis session with redisConf config

func NewRedisSessionAll

func NewRedisSessionAll(redisConf *kv.MyRedisConf, tokenKey, userKey string, expireTime int64, getUserInfoFunc GetUserInfoFunc) (TokenManage, error)

NewRedisSessionAll new a redis session, config all define prefix of token and user key

func NewRedisSessionSimple added in v1.0.13

func NewRedisSessionSimple(redisHost string, redisDB int, redisPass string) (TokenManage, error)

NewRedisSessionSimple new a redis session with simple config

func NewRedisSessionWithPool

func NewRedisSessionWithPool(pool *redis.Pool) (TokenManage, error)

NewRedisSessionWithPool new a redis session by redis pool

type User

type User struct {
	Id                  string      `json:"id"`     // unique mark
	TokenRemainLiveTime int64       `json:"-"`      // token remain live time in cache
	TokenExpireTime     int64       `json:"-"`      // when token expire
	Token               string      `json:"-"`      // this token
	Detail              interface{} `json:"detail"` // can diy your real user info by config ConfigGetUserInfoFunc()
}

User core user info, it's Id will be the primary key store in cache database such redis

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL