DEV Community

luxion
luxion

Posted on

A login authentication Golang library

Token-Go

https://github.com/weloe/token-go

This library focuses on solving login authentication problems, such as: login, multi-account login, shared token, logout, kickout, banned, second auth, temp-token, SSO ...

Features

Using this library can simplify the authentication and authorization business, and only a few lines of code are needed to implement the above business.

Installation

go get github.com/weloe/token-go
Enter fullscreen mode Exit fullscreen mode

Simple Example

import (
    "fmt"
    tokenGo "github.com/weloe/token-go"
    "log"
    "net/http"
)

var enforcer *tokenGo.Enforcer

func main() {
    var err error
    // use default adapter
    adapter := tokenGo.NewDefaultAdapter()
    enforcer, err = tokenGo.NewEnforcer(adapter)
    // enable logger
    enforcer.EnableLog()
    if err != nil {
        log.Fatal(err)
    }

    http.HandleFunc("/user/login", Login)
    http.HandleFunc("/user/logout", Logout)
    http.HandleFunc("/user/isLogin", IsLogin)
    http.HandleFunc("/user/kickout", Kickout)

    log.Fatal(http.ListenAndServe(":8081", nil))
}

func Login(w http.ResponseWriter, req *http.Request) {
    token, err := enforcer.Login("1", tokenGo.NewHttpContext(req, w))
    if err != nil {
        fmt.Fprintf(w, "Login error: %s\n", err)
    }
    fmt.Fprintf(w, "token: %s\n", token)
}

func Logout(w http.ResponseWriter, req *http.Request) {
    err := enforcer.Logout(tokenGo.NewHttpContext(req, w))
    if err != nil {
        fmt.Fprintf(w, "Logout error: %s\n", err)
    }
    fmt.Fprintf(w, "logout success")
}

func IsLogin(w http.ResponseWriter, req *http.Request) {
    login, err := enforcer.IsLogin(tokenGo.NewHttpContext(req, w))
    if err != nil {
        fmt.Fprintf(w, "IsLogin() = %v: %v", login, err)
    }
    fmt.Fprintf(w, "IsLogin() = %v", login)
}

func Kickout(w http.ResponseWriter, req *http.Request) {
    err := enforcer.Kickout(req.URL.Query().Get("id"), "")
    if err != nil {
        fmt.Fprintf(w, "error: %s\n", err)
    }
    fmt.Fprintf(w, "logout success")
}
Enter fullscreen mode Exit fullscreen mode

Custom TokenConfig

The same user can only log in once: IsConcurrent = false && IsShare = false

The same user logs in multiple times and shares a token: IsConcurrent = true && IsShare = true

Multiple logins of the same user to multiple tokens: IsConcurrent = true && IsShare = false

import (
    "fmt"
    tokenGo "github.com/weloe/token-go"
    "github.com/weloe/token-go/config"
    "log"
    "net/http"
)

var enforcer *tokenGo.Enforcer

func main() {
    var err error
    // use default adapter
    adapter := tokenGo.NewDefaultAdapter()
    tokenConfig := &config.TokenConfig{
        TokenName:     "uuid",
        Timeout:       60,
        IsReadCookie:  true,
        IsReadHeader:  true,
        IsReadBody:    false,
        IsConcurrent:  true,
        IsShare:       true,
        MaxLoginCount: -1,
    }
    enforcer, err = tokenGo.NewEnforcer(adapter, tokenConfig)
}
Enter fullscreen mode Exit fullscreen mode

You can also configure it using a yml or ini file like this

token-go/token_conf.ini at master · weloe/token-go · GitHub

token-go/token_conf.yaml at master · weloe/token-go · GitHub

Then use enforcer, err = tokenGo.NewEnforcer(adapter, filepath) to init.

Banned

func TestEnforcer_GetBannedTime(t *testing.T) {
    enforcer, _ := NewTestEnforcer(t)
    var err error
    if err != nil {
        t.Fatalf("NewTestEnforcer() failed: %v", err)
    }
    err = enforcer.Banned("1", "comment", 1, 100)
    if err != nil {
        t.Fatalf("Banned() failed: %v", err)
    }

    t.Logf("banned time = %v", enforcer.GetBannedTime("1", "comment"))

    err = enforcer.Banned("1", "comment", 1, -1)
    if err != nil {
        t.Fatalf("Banned() failed: %v", err)
    }

    t.Logf("banned time = %v", enforcer.GetBannedTime("1", "comment"))

}
Enter fullscreen mode Exit fullscreen mode

Temp-token

func TestEnforcer_TempToken(t *testing.T) {
    enforcer, _ := NewTestEnforcer(t)
    service := "code"
    tempToken, err := enforcer.CreateTempToken("uuid", service, "1234", -1)
    if err != nil {
        t.Fatalf("CreateTempToken() failed: %v", err)
    }
    timeout := enforcer.GetTempTokenTimeout(service, tempToken)
    if timeout != -1 {
        t.Errorf("GetTempTokenTimeout() failed, unexpected timeout: %v", timeout)
    }
    codeValue := enforcer.ParseTempToken("code", tempToken)
    if codeValue != "1234" {
        t.Errorf("ParseTempToken() failed, unexpected codeValue: %v", codeValue)
    }

    // delete
    if enforcer.DeleteTempToken(service, tempToken) != nil {
        t.Fatalf("DeleteTempToken() failed: %v", err)
    }
    tokenTimeout := enforcer.GetTempTokenTimeout(service, tempToken)
    if tokenTimeout != -2 {
        t.Errorf("GetTempTokenTimeout() failed, unexpected tokenTimeout: %v", tokenTimeout)
    }
    codeValue = enforcer.ParseTempToken(service, tempToken)
    if codeValue != "" {
        t.Errorf("ParseTempToken() failed, unexpected codeValue: %v", codeValue)
    }
}
Enter fullscreen mode Exit fullscreen mode

Authorization

A simple permission verification method is also provided

type ACL interface {
    GetPermission(id string) []string
}
Enter fullscreen mode Exit fullscreen mode
type RBAC interface {
    GetRole(id string) []string
}
Enter fullscreen mode Exit fullscreen mode

Implement either of these two interfaces and call enforcer.SetAuth(model)
After that, you can use these two APIs for permission verification

// implement RBAC
CheckRole(ctx ctx.Context, role string) error
// implement ACL
CheckPermission(ctx ctx.Context, permission string) error
Enter fullscreen mode Exit fullscreen mode

example

type Auth struct {
}

func (m *Auth) GetRole(id string) []string {
    var arr = make([]string, 2)
    arr[1] = "user"
    return arr
}
func (m *Auth) GetPermission(id string) []string {
    var arr = make([]string, 2)
    arr[1] = "user::get"
    return arr
}


func main() {
    var err error
    // use default adapter
    adapter := tokenGo.NewDefaultAdapter()
    enforcer, err = tokenGo.NewEnforcer(adapter)
    // set auth
    enforcer.SetAuth(&Auth{})
    // enable logger
    enforcer.EnableLog()
    if err != nil {
        log.Fatal(err)
    }

    http.HandleFunc("/user/check", CheckAuth)

    log.Fatal(http.ListenAndServe(":8081", nil))
}

func CheckAuth(w http.ResponseWriter, req *http.Request) {
    ctx := tokenGo.NewHttpContext(req, w)
    err := enforcer.CheckRole(ctx, "user")
    if err != nil {
        fmt.Fprintf(w, "CheckRole() error: %s\n", err)
        return
    }
    err = enforcer.CheckPermission(ctx, "user::get")
    if err != nil {
        fmt.Fprintf(w, "CheckPermission() error: %s\n", err)
        return
    }
    fmt.Fprintf(w, "you have authorization")
}
Enter fullscreen mode Exit fullscreen mode

SSO

SSO-Server examples: https://github.com/weloe/token-go/blob/master/examples/sso/sso-server/sso-server.go

SSO-Client examples: https://github.com/weloe/token-go/blob/master/examples/sso/sso-client-3/sso-client.go

Extensions

https://github.com/weloe/token-go-extensions

Adapter
RedisAdapter go get github.com/weloe/token-go-extensions/redis-adapter
Enforcer
StatelessEnforcer go get github.com/weloe/token-go-extensions/jwt

Documentation

https://github.com/weloe/token-go/wiki

Api

token_go package - github.com/weloe/token-go - Go Packages

Top comments (0)