func Login(ctx *gin.Context, extra map[string]string) error {
	data := make(map[string]string)
	for key, value := range extra {
		if key == "ip" || key == "hash" || key == "experation" {
			return errors.New("The key '" + key + "' is reserved.")
		}
		data[key] = value
	}
	data["expiration"] = strconv.FormatInt(time.Now().Add(time.Duration(Expiration)*time.Second).Unix(), 10)
	data["ip"] = ip(ctx)
	data["hash"] = hashHeader(ctx)
	SecureCookie = securecookie.New(HashKey, BlockKey)
	if encoded, err := SecureCookie.Encode(CookieName, data); err == nil {
		cookie := http.Cookie{Name: CookieName, Value: encoded, Path: "/", MaxAge: int(Expiration)}
		http.SetCookie(ctx.Writer, &cookie)
	} else {
		return err
	}
	return nil
}
handles the login process
the first param is a map of strings that will be added to the cookie data before encryption and will be
able to be recovered when Check() is called
package ginAuth
import (
	"github.com/gin-gonic/gin"
	"github.com/astaxie/beego/config"
	"github.com/gorilla/securecookie"
	"time"
	"strconv"
	"strings"
	"crypto/md5"
	"encoding/hex"
	"errors"
	"io"
	"net/http"
)
const VERSION = "0.0.1"
var (
	CookieName string                        
	ConfigPath string                        
	ConfigType string                        
	Prefix string                            
	HashKey []byte                           
	BlockKey []byte                          
	Expiration int64                         
	Unauthorized func(ctx *gin.Context)      
	Authorized func(ctx *gin.Context)        
	SecureCookie *securecookie.SecureCookie  
)
func init() {
	ConfigPath = ""
	ConfigType = "ini"
	CookieName = "token"
	Prefix = ""
	Expiration = 604800  
}
func Use(ctx *gin.Context) {
	err := Check(ctx)
	if err == nil {
		loggedIn, _ := ctx.Get(Prefix + "loggedIn")
		if loggedIn == true {
			if Authorized != nil {
				Authorized(ctx)
			}
		} else {
			if Unauthorized != nil {
				Unauthorized(ctx)
			}
		}
	}
}
func LoadConfig() error {
	if ConfigPath != "" {
		conf, err := config.NewConfig(ConfigType, ConfigPath)
		if err != nil {
			return err
		}
		if cookiename := conf.String("cookiename"); cookiename != "" {
			CookieName = cookiename
		}
		if prefix := conf.String("prefix"); prefix != "" {
			Prefix = prefix
		}
		if hashkey := conf.String("hashkey"); hashkey != "" {
			val, err := hex.DecodeString(hashkey)
			if err != nil {
				return err
			}
			HashKey = val
		}
		if blockkey := conf.String("blockkey"); blockkey != "" {
			val, err := hex.DecodeString(blockkey)
			if err != nil {
				return err
			}
			BlockKey = val
		}
		if expiration := conf.String("expiration"); expiration != "" {
			val, err := strconv.ParseInt(expiration, 10, 64)
			if err != nil {
				return err
			}
			Expiration = val
		}
	}
	return nil
}
func saveLogin(ctx *gin.Context, status bool) {
	ctx.Set(Prefix+"loggedIn", status)
}
func ip(ctx *gin.Context) string {
	return strings.Split(ctx.Request.RemoteAddr, ":")[0]
}
func Check(ctx *gin.Context) error {
	cookie, err := ctx.Request.Cookie(CookieName)
	if err == nil {
		data := make(map[string]string)
		SecureCookie = securecookie.New(HashKey, BlockKey)
		if err := SecureCookie.Decode(CookieName, cookie.Value, &data); err == nil {
			ctx.Set(Prefix+"cookieData", data)
			hash := hashHeader(ctx)
			expiration, err := strconv.ParseInt(data["expiration"], 10, 64)
			if err != nil {
				return err
			}
			if hash == data["hash"] && ip(ctx) == data["ip"] && time.Now().Before(time.Unix(expiration, 0)) {
				saveLogin(ctx, true)
			} else {
				Logout(ctx)
			}
		} else {
			return err
		}
	}
	return nil
}