login
This commit is contained in:
parent
5a987b898b
commit
8e0e53af0d
@ -1,7 +1,43 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.tek.govt.hu/dowerx/szoe-pontok/config"
|
||||||
|
"git.tek.govt.hu/dowerx/szoe-pontok/database/auth"
|
||||||
|
"git.tek.govt.hu/dowerx/szoe-pontok/model"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
func Login(c *gin.Context) {
|
func Login(c *gin.Context) {
|
||||||
|
var user model.User
|
||||||
|
if c.MustBindWith(&user, binding.Form) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val := validator.New(validator.WithRequiredStructEnabled())
|
||||||
|
if err := val.Struct(user); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"status": http.StatusBadRequest,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if token, err := auth.Login(user); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"status": http.StatusBadRequest,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.SetCookie("token", token, config.GetConfig().API.TokenLife, "/", "", false, false)
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"status": http.StatusOK,
|
||||||
|
"token": token,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
37
api/auth/middleware.go
Normal file
37
api/auth/middleware.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.tek.govt.hu/dowerx/szoe-pontok/database/auth"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoggedIn(c *gin.Context) {
|
||||||
|
token, err := c.Cookie("token")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"status": http.StatusUnauthorized,
|
||||||
|
"error": "missing token",
|
||||||
|
})
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neptun, err := auth.LoggedIn(token)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"status": http.StatusUnauthorized,
|
||||||
|
"error": "not logged in",
|
||||||
|
})
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set("neptun", neptun)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsAdmin(c *gin.Context) {
|
||||||
|
|
||||||
|
}
|
@ -25,6 +25,19 @@ func Listen(address string, path string) {
|
|||||||
apiAuth.POST("register", auth.Register)
|
apiAuth.POST("register", auth.Register)
|
||||||
apiAuth.GET("login", auth.Login)
|
apiAuth.GET("login", auth.Login)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiTest := api.Group("test").Use(auth.LoggedIn)
|
||||||
|
{
|
||||||
|
apiTest.GET("logged_in", func(c *gin.Context) {
|
||||||
|
neptun, _ := c.Get("neptun")
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"status": http.StatusOK,
|
||||||
|
"message": "if you see this you are logged in",
|
||||||
|
"neptun": neptun,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
|
@ -21,6 +21,7 @@ type Config struct {
|
|||||||
API struct {
|
API struct {
|
||||||
Address string
|
Address string
|
||||||
Path string
|
Path string
|
||||||
|
TokenLife int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ func GetConfig() *Config {
|
|||||||
|
|
||||||
flag.StringVar(&config.API.Address, "api-address", ":5000", "API address")
|
flag.StringVar(&config.API.Address, "api-address", ":5000", "API address")
|
||||||
flag.StringVar(&config.API.Path, "api-path", "api", "API path root")
|
flag.StringVar(&config.API.Path, "api-path", "api", "API path root")
|
||||||
|
flag.IntVar(&config.API.TokenLife, "api-token-life", 24*60*60, "API login token lifetime in seconds")
|
||||||
|
|
||||||
if err := envflag.Parse(); err != nil {
|
if err := envflag.Parse(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
58
database/auth/login.go
Normal file
58
database/auth/login.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.tek.govt.hu/dowerx/szoe-pontok/config"
|
||||||
|
"git.tek.govt.hu/dowerx/szoe-pontok/database"
|
||||||
|
"git.tek.govt.hu/dowerx/szoe-pontok/model"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"golang.org/x/exp/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateToken(length int) string {
|
||||||
|
validRunes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789")
|
||||||
|
token := make([]rune, length)
|
||||||
|
for i := range token {
|
||||||
|
token[i] = validRunes[rand.Intn(len(validRunes))]
|
||||||
|
}
|
||||||
|
return string(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Login(user model.User) (string, error) {
|
||||||
|
db := database.GetDB()
|
||||||
|
|
||||||
|
rows, err := db.NamedQuery(`select "password" from "user" where "neptun" = :neptun and "email" = :email`,
|
||||||
|
map[string]interface{}{
|
||||||
|
"neptun": user.Neptun,
|
||||||
|
"email": user.Email,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
return "", errors.New("no such user")
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash string
|
||||||
|
if err = rows.Scan(&hash); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bcrypt.CompareHashAndPassword([]byte(hash), []byte(user.Password)) != nil {
|
||||||
|
return "", errors.New("wrong password")
|
||||||
|
}
|
||||||
|
|
||||||
|
token := generateToken(32)
|
||||||
|
|
||||||
|
rdb, ctx := database.GetRDB()
|
||||||
|
result := rdb.Set(ctx, token, user.Neptun, time.Duration(config.GetConfig().API.TokenLife)*time.Second)
|
||||||
|
if result.Err() != nil {
|
||||||
|
return "", result.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
23
database/auth/middleware.go
Normal file
23
database/auth/middleware.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.tek.govt.hu/dowerx/szoe-pontok/database"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoggedIn(token string) (string, error) {
|
||||||
|
rdb, ctx := database.GetRDB()
|
||||||
|
result, err := rdb.Get(ctx, token).Result()
|
||||||
|
|
||||||
|
if err == redis.Nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsAdmin(neptun string) error {
|
||||||
|
// db := database.GetDB()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,11 +1,13 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.tek.govt.hu/dowerx/szoe-pontok/config"
|
"git.tek.govt.hu/dowerx/szoe-pontok/config"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
)
|
)
|
||||||
|
|
||||||
var db *sqlx.DB
|
var db *sqlx.DB
|
||||||
@ -22,3 +24,19 @@ func GetDB() *sqlx.DB {
|
|||||||
|
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rdb *redis.Client
|
||||||
|
var ctx context.Context
|
||||||
|
|
||||||
|
func GetRDB() (*redis.Client, context.Context) {
|
||||||
|
if rdb == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
rdb = redis.NewClient(&config.GetConfig().Redis)
|
||||||
|
|
||||||
|
if err := rdb.Ping(ctx).Err(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rdb, ctx
|
||||||
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -32,6 +32,7 @@ require (
|
|||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
golang.org/x/crypto v0.23.0 // indirect
|
golang.org/x/crypto v0.23.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
golang.org/x/text v0.15.0 // indirect
|
golang.org/x/text v0.15.0 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -83,6 +83,8 @@ golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
|||||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||||
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -10,9 +10,9 @@ type User struct {
|
|||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
ID int `db:"id"`
|
ID int `db:"id"`
|
||||||
Description string `db:"description" form:"description"`
|
Description string `db:"description" form:"description" json:"description"`
|
||||||
Points int `db:"points" form:"points" validate:"required"`
|
Points int `db:"points" form:"points" json:"points" validate:"required"`
|
||||||
Recipient string `db:"recipient" form:"recipient" validate:"required,len=6"`
|
Recipient string `db:"recipient" form:"recipient" json:"recipient" validate:"required,len=6"`
|
||||||
Issuer string `db:"issuer" form:"issuer" validate:"required,len=6"`
|
Issuer string `db:"issuer" form:"issuer" json:"issuer" validate:"required,len=6"`
|
||||||
Date time.Time `db:"date"`
|
CreatedDate time.Time `db:"created_date" json:"created_date"`
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user