Skip to content
Permalink
Browse files

[feature] support basic auth header for enforcer

  • Loading branch information...
Soontao committed Aug 11, 2017
1 parent 7814e50 commit 836ac4bf4d22ef061e1a99a386a1916e0732ba71
@@ -12,4 +12,40 @@ documents will be wrote later.

## ARCH

![arch](https://res.cloudinary.com/digf90pwi/image/upload/v1502367434/go-simple-api-gatway_1_grgl5o.png)
![arch](https://res.cloudinary.com/digf90pwi/image/upload/v1502367434/go-simple-api-gatway_1_grgl5o.png)

## CONFIGURATION

You could use **cli option** or **environment varibles** to config your api gateway

```bash
./go-simple-api-gateway --help
Options:
-h, --help display help information
-c, --*conn[=$GATEWAY_CONN_STR] *mysql connection str
-l, --*listen[=$GATEWAY_LS] *gateway listen host and port
-r, --*resource[=$GATEWAY_RESOURCE_URL] *gateway resource url
```

* -c --conn **GATEWAY_CONN_STR**, mysql connection string, format is *user:pass@tcp(domain:port)/dbname*

* -l --listen **GATEWAY_LS**, gateway listen addr, format is *host:port*, example: *0.0.0.0:1329*

* -r --resource **GATEWAY_RESOURCE_URL**, gateway protect target, the resource server, could be a api server, format is *http://host:port*

## DOCKER

you could find docker image from [here](https://hub.docker.com/r/theosun/go-simple-api-gateway/)

example:

```bash
docker run -d --restart=always -p 11329:1329 -e GATEWAY_CONN_STR='user:pass@tcp(mysql:3306)/db_name' -e GATEWAY_LS=':1329' -e GATEWAY_RESOURCE_URL='http://api:1323' --link mariadb:mysql --link citi_api:api --name citi_gateway theosun/go-simple-api-gateway
```

## DOWNLOAD

You could download the latest build binaries from [here](https://download.fornever.org/go-simple-api-gateway/latest/)
@@ -1,7 +1,6 @@
package enforcer

var CasbinConf =
`
var CasbinConf = `
[request_definition]
r = sub, obj, act
@@ -17,6 +16,3 @@ e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
`

var CasbinAnonymousRole = "casbin_anonymous"
var KEY_Username = "username"
@@ -5,7 +5,7 @@ import (
"github.com/casbin/xorm-adapter"
)

func NewCasbinEnforcer(connStr string) (*casbin.Enforcer) {
func NewCasbinEnforcer(connStr string) *casbin.Enforcer {
Adapter := xormadapter.NewAdapter("mysql", connStr, true)
enforcer := casbin.NewEnforcer(casbin.NewModel(CasbinConf), Adapter)
return enforcer
@@ -1,4 +1,4 @@
//From https://github.com/labstack/echo-contrib/casbin
//Based on https://github.com/labstack/echo-contrib/casbin

//License

@@ -27,6 +27,7 @@
package enforcer

import (
"github.com/Soontao/go-simple-api-gateway/key"
"github.com/casbin/casbin"
"github.com/ipfans/echo-session"
"github.com/labstack/echo"
@@ -74,9 +75,9 @@ func MiddlewareWithConfig(config Config) echo.MiddlewareFunc {
return func(c echo.Context) error {
if config.Skipper(c) || config.CheckPermission(c) {
return next(c)
} else {
return echo.ErrForbidden
}

return echo.ErrForbidden
}
}
}
@@ -85,11 +86,11 @@ func MiddlewareWithConfig(config Config) echo.MiddlewareFunc {
// Currently, only HTTP basic authentication is supported
func (a *Config) GetUserName(c echo.Context) (username string) {
sess := session.Default(c)
tmp := sess.Get(KEY_Username)
tmp := sess.Get(key.KEY_Username)
if tmp != nil {
username = tmp.(string)
} else {
username = CasbinAnonymousRole
username = key.KEY_CasbinAnonymous
}
return
}
@@ -0,0 +1,5 @@
package key

var KEY_Username = "username"
var KEY_CasbinAnonymous = "casbin_anonymous"
var KEY_BasicRole = "basic_role"
10 main.go
@@ -1,21 +1,21 @@
package main

import (
"github.com/mkideal/cli"
"github.com/Soontao/go-simple-api-gateway/server"
"github.com/mkideal/cli"
)

type cliArgs struct {
cli.Helper
ConnectionStr string `cli:"*c,*conn" usage:"mysql connection str" dft:"$GATEWAY_CONN_STR"`
AuthServerAddress string `cli:"*a,*auth-ls" usage:"auth server listen host and port" dft:"$GATEWAY_AUTH_SERVER_LS"`
ReverseHost string `cli:"*p,*proxy-target" usage:"reverse proxy target server" dft:"$GATEWAY_REVERSE_HOST"`
ConnectionStr string `cli:"*c,*conn" usage:"mysql connection str" dft:"$GATEWAY_CONN_STR"`
ListenAddr string `cli:"*l,*listen" usage:"gateway listen host and port" dft:"$GATEWAY_LS"`
ResourceURL string `cli:"*r,*resource" usage:"gateway resource url" dft:"$GATEWAY_RESOURCE_URL"`
}

func main() {
cli.Run(new(cliArgs), func(ctx *cli.Context) error {
argv := ctx.Argv().(*cliArgs)
server.NewGatewayServer(argv.ConnectionStr, argv.ReverseHost).Start(argv.AuthServerAddress)
server.NewGatewayServer(argv.ConnectionStr, argv.ResourceURL).Start(argv.ListenAddr)
return nil
})
}
@@ -4,17 +4,17 @@ import (
"fmt"
"net/http"

"github.com/Soontao/go-simple-api-gateway/key"
"github.com/ipfans/echo-session"
"github.com/labstack/echo"
"github.com/Soontao/go-simple-api-gateway/enforcer"
)

func (s *GatewayServer) userAuth(c echo.Context) (err error) {
sess := session.Default(c)
user := User{}
c.Bind(&user)
if s.authUserService.AuthUser(user.Username, user.Password) {
sess.Set(Username, user.Username)
sess.Set(key.KEY_Username, user.Username)
sess.Save()
return c.JSON(http.StatusOK, &DataMessage{http.StatusOK, fmt.Sprintf("auth for %s", user.Username)})
} else {
@@ -53,7 +53,7 @@ func (s *GatewayServer) enforceAuth(c echo.Context) (err error) {
return
}
if p.User == "" {
p.User = enforcer.CasbinAnonymousRole
p.User = key.KEY_CasbinAnonymous
}
passed := s.Enforce(p.User, p.Path, p.Method)
return c.JSON(http.StatusOK, &SuccessMessage{http.StatusOK, passed})
@@ -0,0 +1,22 @@
package server

import (
"github.com/Soontao/go-simple-api-gateway/key"
"github.com/ipfans/echo-session"
"github.com/labstack/echo"
)

// BasicAuthSessionMw is used for reading basic auth header and save username if it passed
func (s *GatewayServer) BasicAuthSessionMw(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
username, password, exist := c.Request().BasicAuth()
sess := session.Default(c)
if exist && username != "" && s.authUserService.AuthUser(username, password) {
sess.Set(key.KEY_Username, username)
} else {
sess.Delete(key.KEY_Username)
}
sess.Save()
return next(c)
}
}
@@ -1,14 +1,14 @@
package server

import (
"github.com/labstack/echo"
_ "github.com/go-sql-driver/mysql"
"github.com/Soontao/go-simple-api-gateway/enforcer"
"github.com/Soontao/go-simple-api-gateway/key"
"github.com/Soontao/go-simple-api-gateway/user"
"github.com/casbin/casbin"
_ "github.com/go-sql-driver/mysql"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"net/url"
"github.com/labstack/gommon/log"
"github.com/Soontao/go-simple-api-gateway/user"
)

type GatewayServer struct {
@@ -21,12 +21,11 @@ type GatewayServer struct {

// NewGatewayServer instance
func NewGatewayServer(connStr string, resourceHostStr string, defaultRole ...string) (s *GatewayServer) {

resourceHost, err := url.Parse(resourceHostStr)

if err != nil {
log.Fatal(err)
panic(err)
}
// construct gateway
s = &GatewayServer{
Echo: echo.New(),
Enforcer: enforcer.NewCasbinEnforcer(connStr),
@@ -37,7 +36,7 @@ func NewGatewayServer(connStr string, resourceHostStr string, defaultRole ...str
if len(defaultRole) == 1 {
s.DefaultRegisterRole = defaultRole[0]
} else {
s.DefaultRegisterRole = "basic_role"
s.DefaultRegisterRole = key.KEY_BasicRole
}

s.Use(NewCoockieSession())
@@ -52,7 +51,7 @@ func NewGatewayServer(connStr string, resourceHostStr string, defaultRole ...str
}

func (s *GatewayServer) mountReverseProxy() {
s.Group("/").Use(enforcer.Middleware(s.Enforcer), middleware.Proxy(&middleware.RoundRobinBalancer{
s.Group("/").Use(s.BasicAuthSessionMw, enforcer.Middleware(s.Enforcer), middleware.Proxy(&middleware.RoundRobinBalancer{
Targets: []*middleware.ProxyTarget{
&middleware.ProxyTarget{
URL: s.resourceHost,
@@ -1,7 +1,5 @@
package server

var Username = "username"

type Policy struct {
User string `json:"user" form:"user" query:"user"`
Path string `json:"path" form:"path" query:"path"`
@@ -28,3 +26,8 @@ type DataMessage struct {
Status int `json:"status" form:"status" query:"status"`
Data interface{}`json:"data" form:"data" query:"data"`
}

type Message struct {
Status int `json:"status" form:"status" query:"status"`
Message interface{}`json:"message" form:"message" query:"message"`
}
@@ -1,13 +1,22 @@
package user

import (
"github.com/satori/go.uuid"
"strings"
"golang.org/x/crypto/bcrypt"
"time"
"strings"
"github.com/satori/go.uuid"
)

// User type
func CryptPass(pass string) string {
bytes, _ := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
return string(bytes)
}

func ComparePassword(hash, password string) error {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
}

// User db model
type User struct {
UUID string `json:"uuid" xorm:"'uuid' pk"`
Username string `json:"username" xorm:"unique"`
@@ -24,12 +33,3 @@ func NewEncryptedUser(username, password string) (u *User) {
u.UUID = strings.Replace(uuid.NewV4().String(), "-", "", -1)
return
}

func CryptPass(pass string) string {
bytes, _ := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
return string(bytes)
}

func ComparePassword(hash, password string) error {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
}
@@ -4,9 +4,10 @@ import (
"encoding/json"
"fmt"
"testing"
"github.com/Soontao/go-simple-api-gateway/types"
)

func TestNewUser(t *testing.T) {
uJson, _ := json.Marshal(NewEncryptedUser("tetsUser", "testPass"))
uJson, _ := json.Marshal(types.NewEncryptedUser("tetsUser", "testPass"))
fmt.Println(string(uJson))
}
@@ -1,8 +1,8 @@
package user

import (
"github.com/go-xorm/xorm"
_ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/xorm"
"github.com/pkg/errors"
)

0 comments on commit 836ac4b

Please sign in to comment.
You can’t perform that action at this time.