sessions

package module
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Feb 23, 2025 License: Apache-2.0 Imports: 15 Imported by: 0

README

Very opinionated gin session middleware with DynamoDB backend

Go Reference

There are already several excellent DynamoDB store plugins for github.com/gin-contrib/sessions (well, mostly from github.com/gorilla/sessions). This module (named sessions) does something a bit different: you must bring your own struct that uses dynamodbav struct tags to model the DynamoDB table that contains session data. When handling a request, you can either work directly with a pointer to this struct, or use a type-safe sessions.Session-compatible implementation that can return an error or panic if you attempt to set a field with the wrong type.

I created this module because I love how easy it is to use the middleware to manage sessions, but I already have my own DynamoDB table for session data. If you're starting new, the various DynamoDB store plugins will abstract away the need to define the DynamoDB schema so you don't have to care about it at all. But if you already have your own table, this module is for you.

Usage

Get with:

go get github.com/nguyengg/go-aws-commons/gin-sessions-dynamodb
package main

import (
	"context"
	"net/http"

	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
	"github.com/gin-gonic/gin"
	sessions "github.com/nguyengg/go-aws-commons/gin-sessions-dynamodb"
	"github.com/nguyengg/go-aws-commons/gin-sessions-dynamodb/groups"
)

type Session struct {
	Id   string `dynamodbav:"sessionId,hashkey" tableName:"session"`
	User *User  `dynamodbav:"user"`
}

type User struct {
	Sub    string   `dynamodbav:"sub"`
	Groups []string `dynamodbav:"groups,stringset"`
}

func main() {
	cfg, err := config.LoadDefaultConfig(context.Background())
	if err != nil {
		panic(err)
	}

	r := gin.Default()
	r.Use(sessions.Sessions[Session]("sid", func(s *sessions.Session) {
		// if you don't explicitly provide a client, `config.LoadDefaultConfig` is used similar to this example.
		s.Client = dynamodb.NewFromConfig(cfg)
	}))

	r.GET("/", func(c *gin.Context) {
		// this is type-safe way to interaction with my session struct.
		var mySession *Session = sessions.Get[Session](c)
		mySession.User = &User{Sub: "henry", Groups: []string{"poweruser"}}
		if err = sessions.Save(c); err != nil {
			_ = c.AbortWithError(http.StatusBadGateway, err)
			return
		}

		// alternatively, I can use the sessions.Session interface "compatible" with gin and gorilla.
		s := sessions.Default(c)
		s.Set("user", "henry")
		if err = s.Save(); err != nil {
			_ = c.AbortWithError(http.StatusBadGateway, err)
			return
		}
	})

	// the module also provides a basic middleware to verify user from the session is authorised based on group
	// membership.
	r.GET("/protected/resource", groups.MustHave(func(c *gin.Context) (bool, groups.Groups) {
		user := sessions.Get[Session](c).User
		if user == nil {
			return false, nil
		}

		return true, user.Groups
	}, groups.OneOf("canReadResource", "canWriteResource")))
}

Documentation

Index

Constants

View Source
const (
	// DefaultKey is the gin context key for Session instance.
	DefaultKey = "github.com/nguyengg/go-aws-commons/gin-sessions-dynamodb"
)

Variables

This section is empty.

Functions

func DefaultNewSessionId

func DefaultNewSessionId() string

DefaultNewSessionId creates a new UUID and returns its raw-URL-encoded content.

func Get

func Get[T interface{}](c *gin.Context) *T

Get returns the pointer to the session struct attached to the request.

There are two ways to interact with the session middleware; this is the more type-safe way.

Usage:

type MySession struct {
	Id string `dynamodbav:"sessionId,hashkey" tableName:"session"`
}

r := gin.Default()
r.Use(Sessions[MySession]("sid"))
r.GET("/", func (c *gin.Context) {
	var s *MySession = Get[MySession](c)
})

func New

func New[T interface{}](c *gin.Context) *T

New always create a new session and return the pointer thereto.

Usage:

type MySession struct {
	Id string `dynamodbav:"sessionId,hashkey" tableName:"session"`
}

r := gin.Default()
r.Use(Sessions[MySession]("sid"))
r.GET("/", func (c *gin.Context) {
	var s *MySession = New[MySession](c)
})

func Save

func Save(c *gin.Context) error

Save can be used to save the current session to DynamoDB.

If you are not using Default and only use the type-safe Get and New, Save can be used instead of Session.Save.

func Sessions

func Sessions[T interface{}](name string, optFns ...func(*Session)) gin.HandlerFunc

Sessions creates a gin middleware for managing sessions of struct type T.

The name argument is the name of the cookie that stores the session Id. Type T must have these struct tags:

// Hash key is required, and its type must be a string since only string session Ids are supported.
Field string `dynamodbav:"sessionId,hashkey" tableName:"my-table"`

See ddb.Table for more information on how the struct tags are parsed. If type T does not implement the required tags or the tags fail validation, the function will panic.

func SetOptions added in v0.1.4

func SetOptions(c *gin.Context, options Options)

SetOptions can be used to modify the cookie options for the current session.

If you are not using Default and only use the type-safe Get and New, SetOptions can be used instead of Session.Options.

Types

type MockDynamoDBClient

type MockDynamoDBClient struct {
	mock.Mock
	dynamodb.Client
}

func (*MockDynamoDBClient) DeleteItem

func (m *MockDynamoDBClient) DeleteItem(ctx context.Context, params *dynamodb.DeleteItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DeleteItemOutput, error)

func (*MockDynamoDBClient) GetItem

func (m *MockDynamoDBClient) GetItem(ctx context.Context, params *dynamodb.GetItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.GetItemOutput, error)

func (*MockDynamoDBClient) PutItem

func (m *MockDynamoDBClient) PutItem(ctx context.Context, params *dynamodb.PutItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.PutItemOutput, error)

func (*MockDynamoDBClient) UpdateItem

func (m *MockDynamoDBClient) UpdateItem(ctx context.Context, params *dynamodb.UpdateItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateItemOutput, error)

type Options

type Options = sessions.Options

Options stores configuration for a session or session store. Fields are a subset of http.Cookie fields.

This is a clone from "github.com/gin-contrib/sessions" and "github.com/gorilla/sessions" which are both named "sessions" to help you not having to name your import conflicts.

type Session

type Session struct {
	// Client is the DynamoDB client for saving session data.
	//
	// By default, `config.LoadDefaultConfig` will be used to provide an instance.
	Client ddb.ManagerAPIClient

	// ClientOptions is passed to every DynamoDB call.
	ClientOptions []func(*dynamodb.Options)

	// NewSessionId is used to create the Id for a new session.
	//
	// By default, DefaultNewSessionId is used.
	NewSessionId func() string

	// CookieOptions modify the cookie settings.
	CookieOptions sessions.Options
	// contains filtered or unexported fields
}

Session implements gin sessions.Session in a type-safe way.

func Default

func Default(c *gin.Context) *Session

Default returns the Session instance attached to the request.

There are two ways to interact with the session middleware; this is one of them by letting you interact with the Session wrapper.

func (*Session) AddFlash

func (s *Session) AddFlash(value interface{}, vars ...string)

func (*Session) Clear

func (s *Session) Clear()

Clear deletes all values in the session.

The hashkey (session Id) will not be deleted, and any fields not tagged with `dynamodbav` will also be ignored.

func (*Session) Delete

func (s *Session) Delete(key interface{})

func (*Session) Flashes

func (s *Session) Flashes(vars ...string) []interface{}

func (*Session) Get

func (s *Session) Get(key interface{}) interface{}

func (*Session) ID

func (s *Session) ID() string

func (*Session) Options

func (s *Session) Options(options Options)

func (*Session) Save

func (s *Session) Save() error

func (*Session) Set

func (s *Session) Set(key interface{}, val interface{})

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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