added adduser registeruser changepassword deluser changeuser

This commit is contained in:
wt committed 2025-05-27 22:07:50 +07:00
1 parent 55dbc36b92
commit c65d6d5be5
8 files changed
+211 -24

No files matched your search

+5 -5
View File
@@ -14,7 +14,7 @@ import (
const defaultsecretkey = "secret" const defaultsecretkey = "secret"
func createJWT(secretKey string, data map[string]interface{}, ttl time.Duration) (string, error) { func createJWT(secretKey string, data map[string]any, ttl time.Duration) (string, error) {
claims := jwt.MapClaims{ claims := jwt.MapClaims{
"exp": time.Now().Add(ttl).Unix(), "exp": time.Now().Add(ttl).Unix(),
"iat": time.Now().Unix(), "iat": time.Now().Unix(),
@@ -29,10 +29,10 @@ func createJWT(secretKey string, data map[string]interface{}, ttl time.Duration)
return signedToken, nil return signedToken, nil
} }
func VerifyJWT(tokenString string, secretKey string) (map[string]interface{}, error) { func VerifyJWT(tokenString string, secretKey string) (map[string]any, error) {
token, e := jwt.Parse( token, e := jwt.Parse(
tokenString, tokenString,
func(token *jwt.Token) (interface{}, error) { func(token *jwt.Token) (any, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpexted signing method: %v", token.Header["alg"]) return nil, fmt.Errorf("unexpexted signing method: %v", token.Header["alg"])
} }
@@ -43,7 +43,7 @@ func VerifyJWT(tokenString string, secretKey string) (map[string]interface{}, er
return nil, fmt.Errorf("token validation failed: %w", e) return nil, fmt.Errorf("token validation failed: %w", e)
} }
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
result := make(map[string]interface{}) result := make(map[string]any)
for key, value := range claims { for key, value := range claims {
if key == "exp" || key == "iat" || key == "nbf" { if key == "exp" || key == "iat" || key == "nbf" {
continue continue
@@ -74,7 +74,7 @@ func Token(w http.ResponseWriter, req *http.Request) {
IsSuperuser: dbuser.IsSuperuser, IsSuperuser: dbuser.IsSuperuser,
} }
responseUserMarshal, _ := json.Marshal(responseUser) responseUserMarshal, _ := json.Marshal(responseUser)
responseUserUnmarshal := make(map[string]interface{}) responseUserUnmarshal := make(map[string]any)
json.Unmarshal(responseUserMarshal, &responseUserUnmarshal) json.Unmarshal(responseUserMarshal, &responseUserUnmarshal)
token, _ := createJWT(defaultsecretkey, responseUserUnmarshal, time.Duration(24*time.Hour)) token, _ := createJWT(defaultsecretkey, responseUserUnmarshal, time.Duration(24*time.Hour))
fmt.Fprintf(w, "{\"token\":\"%s\"}", token) fmt.Fprintf(w, "{\"token\":\"%s\"}", token)
+138 -5
View File
@@ -6,6 +6,8 @@ import (
"form/database" "form/database"
"form/model" "form/model"
"net/http" "net/http"
"github.com/google/uuid"
) )
func GetAllUsers(w http.ResponseWriter, req *http.Request) { func GetAllUsers(w http.ResponseWriter, req *http.Request) {
@@ -65,25 +67,156 @@ func GetUser(w http.ResponseWriter, req *http.Request) {
func ChangePassword(w http.ResponseWriter, req *http.Request) { func ChangePassword(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var request model.ChangePasswordRequest
decoder := json.NewDecoder(req.Body)
decoder.Decode(&request)
claims, e := VerifyJWT(request.Token, defaultsecretkey)
if e != nil {
fmt.Fprintf(w, "{\"status\": 403}")
return
}
user, e := database.GetUserByUsername(fmt.Sprintf("%v", claims["username"]))
if e != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", e)
return
}
if user.Password == request.OldPassword {
database.Db.Model(&user).Update("Password", request.NewPassword)
fmt.Fprint(w, "{\"status\":200}")
return
}
fmt.Fprintf(w, "{\"status\":403}")
} }
func DelUser(w http.ResponseWriter, req *http.Request) { func DelUser(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var request model.DelUserRequest
decoder := json.NewDecoder(req.Body)
decoder.Decode(&request)
claims, e := VerifyJWT(request.Token, defaultsecretkey)
if e != nil {
fmt.Fprintf(w, "{\"status\": 403}")
return
}
if claims["is_superuser"] == true || request.UserId != "" {
user, e := database.GetUserById(request.UserId)
if e != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", e)
return
}
e = database.DeleteUser(user.Id)
if e != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", e)
return
}
fmt.Fprintf(w, "{\"status\":200}")
return
}
e = database.DeleteUser(fmt.Sprintf("%v", claims["id"]))
if e != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", e)
return
}
fmt.Fprint(w, "{\"status\":200}")
} }
func AddUser(w http.ResponseWriter, req *http.Request) { func AddUser(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var request model.AddUserRequest
decoder := json.NewDecoder(req.Body)
decoder.Decode(&request)
claims, e := VerifyJWT(request.Token, defaultsecretkey)
if e != nil {
fmt.Fprintf(w, "{\"status\": 403}")
return
}
if claims["is_superuser"] == true {
id, err := uuid.NewRandom()
if err != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", err)
return
}
_, e := database.GetUserByUsername(request.Username)
if e != nil {
e = database.CreateUser(&model.User{
Id: id.String(),
Username: request.Username,
Email: request.Email,
Password: request.Password,
Group: request.Group,
IsSuperuser: request.IsSuperuser,
})
if e != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", e)
return
}
fmt.Fprintf(w, "{\"status\": 200}")
return
}
fmt.Fprintf(w, "{\"error\":\"username already exists\"}")
return
}
fmt.Fprintf(w, "{\"status\":403}")
} }
func RegisterUser(w http.ResponseWriter, req *http.Request) { func RegisterUser(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var request model.AddUserRequest
decoder := json.NewDecoder(req.Body)
decoder.Decode(&request)
if request.Username == "" {
fmt.Fprintf(w, "{\"error\":\"need more data\"}")
return
}
id, err := uuid.NewRandom()
if err != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", err)
return
}
group := "users"
if request.Group != "" {
group = request.Group
}
_, e := database.GetUserByUsername(request.Username)
if e != nil {
e = database.CreateUser(&model.User{
Id: id.String(),
Username: request.Username,
Email: request.Email,
Password: request.Password,
Group: group,
IsSuperuser: request.IsSuperuser,
})
if e != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", e)
return
}
fmt.Fprintf(w, "{\"status\": 200}")
return
}
fmt.Fprintf(w, "{\"error\":\"username already exists\"}")
} }
func ChangeUser(w http.ResponseWriter, req *http.Request) { func ChangeUser(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var request model.ChangeUserRequest
decoder := json.NewDecoder(req.Body)
decoder.Decode(&request)
claims, e := VerifyJWT(request.Token, defaultsecretkey)
if e != nil {
fmt.Fprintf(w, "{\"status\": 403}")
return
}
user, e := database.GetUserByUsername(fmt.Sprintf("%v", claims["username"]))
if e != nil {
fmt.Fprintf(w, "{\"error\":\"%v\"}", e)
return
}
database.Db.Model(&user).Updates(map[string]any{
"Username": request.Username,
"Email": request.Email,
"Group": request.Group,
"IsSuperuser": request.IsSuperuser,
})
fmt.Fprint(w, "{\"status\":200}")
} }
+3
View File
@@ -0,0 +1,3 @@
USERS_FILE=users.json
USERS_DB=users.db
ENABLE_SELF_REGISTER=false
+4 -3
View File
@@ -3,16 +3,17 @@ package database
import ( import (
"fmt" "fmt"
"form/model" "form/model"
"os"
"gorm.io/driver/sqlite" "gorm.io/driver/sqlite"
"gorm.io/gorm" "gorm.io/gorm"
) )
var db *gorm.DB var Db *gorm.DB
func Init() error { func Init() error {
var err error var err error
db, err = gorm.Open(sqlite.Open("users.db"), &gorm.Config{}) Db, err = gorm.Open(sqlite.Open(os.Getenv("USERS_DB")), &gorm.Config{})
if err != nil { if err != nil {
fmt.Println("failed to connect database") fmt.Println("failed to connect database")
return err return err
@@ -21,5 +22,5 @@ func Init() error {
} }
func Migrate() { func Migrate() {
db.AutoMigrate(&model.User{}) Db.AutoMigrate(&model.User{})
} }
+6 -6
View File
@@ -12,7 +12,7 @@ import (
) )
func CreateUser(user *model.User) error { func CreateUser(user *model.User) error {
e := db.Where(model.User{ e := Db.Where(model.User{
Username: user.Username, Username: user.Username,
}).FirstOrCreate(&user).Error }).FirstOrCreate(&user).Error
if e != nil { if e != nil {
@@ -23,7 +23,7 @@ func CreateUser(user *model.User) error {
func GetUserById(id string) (*model.User, error) { func GetUserById(id string) (*model.User, error) {
var user model.User var user model.User
e := db.First(&user, "id = ?", id).Error e := Db.First(&user, "id = ?", id).Error
if e != nil { if e != nil {
if errors.Is(e, gorm.ErrRecordNotFound) { if errors.Is(e, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("user not found") return nil, fmt.Errorf("user not found")
@@ -35,7 +35,7 @@ func GetUserById(id string) (*model.User, error) {
func GetUserByUsername(username string) (*model.User, error) { func GetUserByUsername(username string) (*model.User, error) {
var user model.User var user model.User
e := db.First(&user, "username = ?", username).Error e := Db.First(&user, "username = ?", username).Error
if e != nil { if e != nil {
if errors.Is(e, gorm.ErrRecordNotFound) { if errors.Is(e, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("user not found") return nil, fmt.Errorf("user not found")
@@ -47,14 +47,14 @@ func GetUserByUsername(username string) (*model.User, error) {
func DeleteUser(id string) error { func DeleteUser(id string) error {
var user model.User var user model.User
e := db.First(&user, "id = ?", id).Error e := Db.First(&user, "id = ?", id).Error
if e != nil { if e != nil {
if errors.Is(e, gorm.ErrRecordNotFound) { if errors.Is(e, gorm.ErrRecordNotFound) {
return fmt.Errorf("user not found") return fmt.Errorf("user not found")
} }
return e return e
} }
e = db.Delete(&user).Error e = Db.Unscoped().Delete(&user).Error
if e != nil { if e != nil {
if errors.Is(e, gorm.ErrRecordNotFound) { if errors.Is(e, gorm.ErrRecordNotFound) {
return fmt.Errorf("user not found") return fmt.Errorf("user not found")
@@ -77,7 +77,7 @@ func GetUsersFromFile(filename string) []model.User {
func GetAllUsers() ([]model.User, error) { func GetAllUsers() ([]model.User, error) {
var users []model.User var users []model.User
e := db.Find(&users).Error e := Db.Find(&users).Error
if e != nil { if e != nil {
return nil, e return nil, e
} }
+2
View File
@@ -4,6 +4,8 @@ go 1.24.3
require ( require (
github.com/golang-jwt/jwt/v5 v5.2.2 github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
gorm.io/driver/sqlite v1.5.7 gorm.io/driver/sqlite v1.5.7
gorm.io/gorm v1.30.0 gorm.io/gorm v1.30.0
) )
+17 -5
View File
@@ -3,28 +3,40 @@ package main
import ( import (
"form/api" "form/api"
"form/database" "form/database"
"log"
"net/http" "net/http"
"os"
"github.com/joho/godotenv"
) )
func main() { func main() {
err := godotenv.Load("auth_service.config")
if err != nil {
log.Fatal("Error loading .env file")
}
database.Init() database.Init()
database.Migrate() database.Migrate()
users := database.GetUsersFromFile("users.json") if os.Getenv("USERS_FILE") != "" {
for i := range users { users := database.GetUsersFromFile(os.Getenv("USERS_FILE"))
database.CreateUser(&users[i]) for i := range users {
database.CreateUser(&users[i])
}
} }
http.HandleFunc("/api/token", api.Token) http.HandleFunc("/api/token", api.Token)
http.HandleFunc("/api/token/verify", api.VerifyToken) http.HandleFunc("/api/token/verify", api.VerifyToken)
http.HandleFunc("/api/access", api.VerifyToken) http.HandleFunc("/api/access", api.VerifyToken)
http.HandleFunc("/api/register", api.RegisterUser) if os.Getenv("ENABLE_SELF_REGISTER") == "true" {
http.HandleFunc("/api/register", api.RegisterUser)
}
http.HandleFunc("/api/users", api.GetAllUsers) http.HandleFunc("/api/users", api.GetAllUsers)
http.HandleFunc("/api/users/user", api.GetUser) http.HandleFunc("/api/users/user", api.GetUser)
http.HandleFunc("/api/users/password", api.ChangePassword) http.HandleFunc("/api/users/password", api.ChangePassword)
http.HandleFunc("/api/users/change", api.ChangeUser) http.HandleFunc("/api/users/change", api.ChangeUser)
http.HandleFunc("/api/users/del", api.DelUser) http.HandleFunc("/api/users/del", api.DelUser)
http.HandleFunc("/api/user/add", api.AddUser) http.HandleFunc("/api/users/add", api.AddUser)
http.ListenAndServe(":8090", nil) http.ListenAndServe(":8090", nil)
} }
+36
View File
@@ -32,3 +32,39 @@ type Token struct {
type GetAllUsersRequest struct { type GetAllUsersRequest struct {
Token string `json:"token"` Token string `json:"token"`
} }
type ChangePasswordRequest struct {
Token string `json:"token"`
OldPassword string `json:"old_password"`
NewPassword string `json:"new_password"`
}
type ChangeUserRequest struct {
Token string `json:"token"`
Username string `json:"username"`
Email string `json:"email"`
Group string `json:"group"`
IsSuperuser bool `json:"is_superuser"`
}
type DelUserRequest struct {
Token string `json:"token"`
UserId string `json:"user_id,omitempty"`
}
type AddUserRequest struct {
Token string `json:"token"`
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
Group string `json:"group"`
IsSuperuser bool `json:"is_superuser"`
}
type RegusterUserRequest struct {
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
Group string `json:"group"`
IsSuperuser bool `json:"is_superuser"`
}