Browse Source

authentication middleware added

master
Bernd-René Predota 5 years ago
parent
commit
f1429e07ea
  1. 2
      README.md
  2. 9
      api/v1/users/route.go
  3. 32
      api/v1/users/users.go
  4. 37
      cmd/server/server.go
  5. 21
      lib/authentication/authentication.go
  6. 7
      lib/cache/cache.go
  7. 49
      lib/middlewares/authentication.go

2
README.md

@ -1,6 +1,6 @@
# golang API Skeleton
[![Build Status](https://drone.devices.local/api/badges/mawas/golang-api-skeleton/status.svg)](https://drone.devices.local/mawas/golang-api-skeleton)<a href='https://github.com/jpoles1/gopherbadger' target='_blank'>![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-69%25-brightgreen.svg?longCache=true&style=flat)</a>
[![Build Status](https://drone.devices.local/api/badges/mawas/golang-api-skeleton/status.svg)](https://drone.devices.local/mawas/golang-api-skeleton)<a href='https://github.com/jpoles1/gopherbadger' target='_blank'>![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-77%25-brightgreen.svg?longCache=true&style=flat)</a>
refined skeleton future apis should be based on

9
api/v1/users/route.go

@ -1,14 +1,17 @@
package users
import "github.com/gin-gonic/gin"
import (
"git.devices.local/mawas/golang-api-skeleton/lib/authentication"
"github.com/gin-gonic/gin"
)
// ApplyRoutes applies router to the gin Engine
func ApplyRoutes(r *gin.RouterGroup) *gin.RouterGroup {
users := r.Group("/users")
{
// actions.POST("", middlewares.Authorized, CreateActions)
// actions.GET("/:id", middlewares.Authorized, ReadAction)
users.GET("/:username", Read)
users.GET("/:username", authentication.Authorized, ReadByID)
users.GET("", authentication.Authorized, ReadAll)
// actions.GET("/:id/logs", middlewares.Authorized, actionlogs.ReadActionLogs)
// actions.PATCH("/:id", middlewares.Authorized, UpdateAction)
// actions.PATCH("", middlewares.Authorized, UpdateActions)

32
api/v1/users/users.go

@ -9,19 +9,37 @@ import (
"gorm.io/gorm"
)
func Read(c *gin.Context) {
db := c.MustGet("db").(*gorm.DB)
cc := c.MustGet("cache").(cache.Cache)
response := response.Envelope{
func prepare(c *gin.Context) (response.Envelope, *services.UserService) {
resp := response.Envelope{
RequestID: c.MustGet("requestID").(string),
}
userRepo := repositories.NewUserRepository(db, "01F5FSJXDHWT4HK93B9NB8V5G4", "test", cc)
userRepo := repositories.NewUserRepository(
c.MustGet("db").(*gorm.DB),
c.MustGet("userID").(string),
c.MustGet("username").(string),
c.MustGet("cache").(cache.Cache),
)
userService := services.NewUserService(userRepo)
return resp, userService
}
func ReadByID(c *gin.Context) {
resp, userService := prepare(c)
username := c.Param("username")
user, err := userService.ReadByID(username)
if err != nil {
c.AbortWithStatusJSON(500, response.AppendError(err))
c.AbortWithStatusJSON(500, resp.AppendError(err))
return
}
c.JSON(200, resp.SetSuccess(user))
}
func ReadAll(c *gin.Context) {
resp, userService := prepare(c)
users, err := userService.ReadAll()
if err != nil {
c.AbortWithStatusJSON(500, resp.AppendError(err))
return
}
c.JSON(200, response.SetSuccess(user))
c.JSON(200, resp.SetSuccess(users))
}

37
cmd/server/server.go

@ -71,23 +71,38 @@ func startServer(version string, appName string, cfgFile string, flagCfg map[str
}
// Prefill cache
// TODO also add deleted users to cache for old references
// users
userRepo := repositories.NewUserRepository(db, common.CLIUserID, common.CLIUsername, nil)
userService := services.NewUserService(userRepo)
if userData, err := userService.ReadAll(); err != nil {
} else {
for i := range userData {
if err := c.Set("user:"+userData[i].ID.String(), userData[i].Username); err != nil { // userID -> username mapping
return fmt.Errorf("cache:%v", err)
}
if err := c.Set("user:"+userData[i].Username, userData[i].ID.String()); err != nil { // username -> userID mapping
return fmt.Errorf("cache:%v", err)
}
userData, err := userService.ReadAll()
if err != nil {
return fmt.Errorf("cache:%v", err)
}
for i := range userData {
if err := c.Set("user:"+userData[i].ID.String(), userData[i].Username); err != nil { // userID -> username mapping
return fmt.Errorf("cache:%v", err)
}
if err := c.Set("user:"+userData[i].Username, userData[i].ID.String()); err != nil { // username -> userID mapping
return fmt.Errorf("cache:%v", err)
}
}
// tokens
tokenRepo := repositories.NewTokenRepository(db, common.CLIUserID, common.CLIUsername, nil)
tokenService := services.NewTokenService(tokenRepo)
tokenData, err := tokenService.ReadAll()
if err != nil {
return fmt.Errorf("cache:%v", err)
}
for i := range tokenData {
if err := c.Set("token:"+tokenData[i].Token.String(), tokenData[i].UserID.String()); err != nil { // token -> userID mapping
return fmt.Errorf("cache:%v", err)
}
}
app.Use(middlewares.RequestID())
app.Use(middlewares.VersionHeader(version))
app.Use(inject("cache", c))
app.Use(inject("db", db))
app.Use(middlewares.RequestID())
app.Use(middlewares.Authentication())
app.Use(middlewares.VersionHeader(version))
// FIXME find out where todo database migration
if err := db.AutoMigrate(&models.Token{}); err != nil {
return fmt.Errorf("database:%v", err)

21
lib/authentication/authentication.go

@ -0,0 +1,21 @@
package authentication
import (
"errors"
"fmt"
"git.devices.local/mawas/golang-api-skeleton/lib/response"
"github.com/gin-gonic/gin"
)
// Authorized blocks unauthorized requestors
func Authorized(c *gin.Context) {
var resp response.Envelope
userID, exists := c.Get("userID")
if !exists {
c.AbortWithStatusJSON(403, resp.AppendError(errors.New("unauthorized")))
return
}
fmt.Println("permission check", userID)
// TODO add cache perm check here
}

7
lib/cache/cache.go

@ -63,8 +63,11 @@ func (cache bCache) Get(key string) (*string, error) {
}); err != nil {
return nil, err
}
r := string(result)
return &r, nil
if len(result) > 0 {
r := string(result)
return &r, nil
}
return nil, nil
}
// SetWithTTL sets a cache entry

49
lib/middlewares/authentication.go

@ -0,0 +1,49 @@
package middlewares
import (
"strings"
"git.devices.local/mawas/golang-api-skeleton/lib/cache"
"github.com/gin-gonic/gin"
)
func Authentication() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString, err := c.Cookie("token")
appCache := c.MustGet("cache").(cache.Cache)
// failed to read cookie
if err != nil {
// try reading HTTP Header
authorization := c.Request.Header.Get("Authorization")
if authorization == "" {
c.Next()
return
}
sp := strings.Split(authorization, "Bearer ")
// invalid token
if len(sp) < 2 {
c.Next()
return
}
tokenString = sp[1]
}
// https://datatracker.ietf.org/doc/rfc8959/?include_text=1
userID, err := appCache.Get("token:" + tokenString)
if err != nil {
c.Next()
return
}
if userID != nil {
username, err := appCache.Get("user:" + *userID)
if err != nil {
c.Next()
return
}
if username != nil {
c.Set("username", *username)
}
c.Set("userID", *userID)
}
c.Next()
}
}
Loading…
Cancel
Save