From 10d313d2b579d019ab7b8eb43a7bad43ef5880f6 Mon Sep 17 00:00:00 2001 From: xc Date: Wed, 19 Nov 2025 18:47:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E7=94=A8=E6=88=B7=E8=A1=A8?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aufs/core/login.go | 272 ++++++++++++++++++++++++++++++++++++++++++++ aufs/db/dbconst.go | 15 +++ aufs/db/dbuser.go | 165 +++++++++++++++++++++++++++ aufs/db/sqliteDb.go | 33 ++++++ 4 files changed, 485 insertions(+) create mode 100644 aufs/core/login.go create mode 100644 aufs/db/dbuser.go diff --git a/aufs/core/login.go b/aufs/core/login.go new file mode 100644 index 0000000..a6a0ffc --- /dev/null +++ b/aufs/core/login.go @@ -0,0 +1,272 @@ +package core + +import ( + "encoding/json" + "errors" + "net/http" + "time" + "aufs/crypto" + "aufs/db" +) + +// LoginRequest 登录请求结构 +type LoginRequest struct { + Username string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` +} + +// LoginResponse 登录响应结构 +type LoginResponse struct { + Token string `json:"token"` + User User `json:"user"` + ExpiresAt time.Time `json:"expires_at"` +} + +// User 用户数据结构 +type User struct { + ID int `json:"id" db:"id"` + Username string `json:"username" db:"username"` + Email string `json:"email" db:"email"` + Role string `json:"role" db:"role"` + CreatedAt time.Time `json:"created_at" db:"created_at"` + UpdatedAt time.Time `json:"updated_at" db:"updated_at"` + LastLogin time.Time `json:"last_login" db:"last_login"` + Status string `json:"status" db:"status"` // active, locked, deleted +} + +// 处理登录传入的数据 +func LoginHandler(w http.ResponseWriter, r *http.Request) { + // 解析请求体中的JSON数据 + var loginReq LoginRequest + err := json.NewDecoder(r.Body).Decode(&loginReq) + if err != nil { + http.Error(w, "Invalid request payload", http.StatusBadRequest) + return + } + + // 验证用户名和密码 + user, err := authenticateUser(loginReq.Username, loginReq.Password) + if err != nil { + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + + // 生成访问令牌(这里简化处理,实际项目中可能需要使用JWT等) + token := "temp_token_" + time.Now().Format("20060102150405") + expiresAt := time.Now().Add(24 * time.Hour) // 令牌有效期24小时 + + // 更新用户最后登录时间 + err = db.UpdateUserLastLogin(user.ID) + if err != nil { + // 记录错误但不影响登录流程 + // 实际项目中应该有日志记录 + } + + // 构建响应 + response := LoginResponse{ + Token: token, + User: *user, + ExpiresAt: expiresAt, + } + + // 返回JSON响应 + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +} + +// 用户状态常量 +const ( + UserStatusActive = "active" + UserStatusLocked = "locked" + UserStatusDeleted = "deleted" +) + +// RegisterRequest 注册请求结构 +type RegisterRequest struct { + Username string `json:"username" binding:"required"` + Email string `json:"email" binding:"required"` + Password string `json:"password" binding:"required"` +} + +// RegisterResponse 注册响应结构 +type RegisterResponse struct { + User User `json:"user"` + Message string `json:"message"` + CreatedAt time.Time `json:"created_at"` +} + +// RegisterHandler 处理用户注册 +func RegisterHandler(w http.ResponseWriter, r *http.Request) { + // 解析请求体中的JSON数据 + var registerReq RegisterRequest + err := json.NewDecoder(r.Body).Decode(®isterReq) + if err != nil { + http.Error(w, "Invalid request payload", http.StatusBadRequest) + return + } + + // 检查用户名是否已存在 + usernameExists, err := db.CheckUsernameExists(registerReq.Username) + if err != nil { + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + if usernameExists { + http.Error(w, "Username already exists", http.StatusConflict) + return + } + + // 检查邮箱是否已存在 + emailExists, err := db.CheckEmailExists(registerReq.Email) + if err != nil { + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + if emailExists { + http.Error(w, "Email already exists", http.StatusConflict) + return + } + + // 对密码进行哈希处理 + hashedPassword, err := crypto.HashPassword(registerReq.Password) + if err != nil { + http.Error(w, "Failed to process password", http.StatusInternalServerError) + return + } + + // 创建用户对象 + userDB := db.User{ + Username: registerReq.Username, + Email: registerReq.Email, + PasswordHash: hashedPassword, + Role: "user", // 默认角色 + Status: UserStatusActive, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + LastLogin: time.Time{}, // 初始为零值 + } + + // 保存用户到数据库 + createdUser, err := db.AddUser(userDB) + if err != nil { + http.Error(w, "Failed to create user", http.StatusInternalServerError) + return + } + + // 转换为core包的User对象 + user := User{ + ID: createdUser.ID, + Username: createdUser.Username, + Email: createdUser.Email, + Role: createdUser.Role, + CreatedAt: createdUser.CreatedAt, + UpdatedAt: createdUser.UpdatedAt, + LastLogin: createdUser.LastLogin, + Status: createdUser.Status, + } + + // 构建响应 + response := RegisterResponse{ + User: user, + Message: "User registered successfully", + CreatedAt: user.CreatedAt, + } + + // 返回JSON响应 + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(response) +} + +// ResetPasswordRequest 重置密码请求结构 +type ResetPasswordRequest struct { + Username string `json:"username" binding:"required"` + NewPassword string `json:"new_password" binding:"required"` +} + +// ResetPasswordResponse 重置密码响应结构 +type ResetPasswordResponse struct { + Message string `json:"message"` + UpdatedAt time.Time `json:"updated_at"` +} + +// ResetPasswordHandler 处理密码重置 +func ResetPasswordHandler(w http.ResponseWriter, r *http.Request) { + // 解析请求体中的JSON数据 + var resetReq ResetPasswordRequest + err := json.NewDecoder(r.Body).Decode(&resetReq) + if err != nil { + http.Error(w, "Invalid request payload", http.StatusBadRequest) + return + } + + // 检查用户是否存在 + userDB, err := db.GetUserByUsername(resetReq.Username) + if err != nil { + http.Error(w, "User not found", http.StatusNotFound) + return + } + + // 检查用户状态 + if userDB.Status != UserStatusActive { + http.Error(w, "User account is locked or disabled", http.StatusForbidden) + return + } + + // 对新密码进行哈希处理 + hashedPassword, err := crypto.HashPassword(resetReq.NewPassword) + if err != nil { + http.Error(w, "Failed to process new password", http.StatusInternalServerError) + return + } + + // 更新用户密码 + updatedAt := time.Now() + err = db.UpdateUserPassword(userDB.ID, hashedPassword, updatedAt) + if err != nil { + http.Error(w, "Failed to update password", http.StatusInternalServerError) + return + } + + // 构建响应 + response := ResetPasswordResponse{ + Message: "Password reset successful", + UpdatedAt: updatedAt, + } + + // 返回JSON响应 + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +} + +// authenticateUser 验证用户身份 +func authenticateUser(username, password string) (*User, error) { + // 根据用户名查询用户信息 + userDB, err := db.GetUserByUsername(username) + if err != nil { + return nil, errors.New("用户名或密码错误") + } + + // 检查用户状态 + if userDB.Status != UserStatusActive { + return nil, errors.New("用户账号已被锁定或禁用") + } + + // 验证密码 + isValid, err := crypto.VerifyPassword(userDB.PasswordHash, password) + if err != nil || !isValid { + return nil, errors.New("用户名或密码错误") + } + + // 转换为core包的User对象 + return &User{ + ID: userDB.ID, + Username: userDB.Username, + Email: userDB.Email, + Role: userDB.Role, + CreatedAt: userDB.CreatedAt, + UpdatedAt: userDB.UpdatedAt, + LastLogin: userDB.LastLogin, + Status: userDB.Status, + }, nil +} diff --git a/aufs/db/dbconst.go b/aufs/db/dbconst.go index e6d929a..21f9e6e 100644 --- a/aufs/db/dbconst.go +++ b/aufs/db/dbconst.go @@ -1,5 +1,7 @@ package db +import "time" + // 定义数据库中用的模型 type StFileInfo struct { Id string `json:"id"` @@ -17,3 +19,16 @@ type StServerInfo struct { Token string `json:"token"` Status int `json:"status"` } + +// 用户信息 +type User struct { + ID int `json:"id" db:"id"` + Username string `json:"username" db:"username"` + Email string `json:"email" db:"email"` + Role string `json:"role" db:"role"` + CreatedAt time.Time `json:"created_at" db:"created_at"` + UpdatedAt time.Time `json:"updated_at" db:"updated_at"` + LastLogin time.Time `json:"last_login" db:"last_login"` + Status string `json:"status" db:"status"` + PasswordHash string `json:"-" db:"password_hash"` +} diff --git a/aufs/db/dbuser.go b/aufs/db/dbuser.go new file mode 100644 index 0000000..7ae83b6 --- /dev/null +++ b/aufs/db/dbuser.go @@ -0,0 +1,165 @@ +package db + +import ( + "database/sql" + "time" +) + +// CreateUserTable 创建用户表 +func CreateUserTable(db *sql.DB) error { + createTableSQL := ` + CREATE TABLE IF NOT EXISTS sc_user ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username VARCHAR(50) NOT NULL UNIQUE, + email VARCHAR(100) NOT NULL UNIQUE, + password_hash VARCHAR(255) NOT NULL, + role VARCHAR(20) NOT NULL DEFAULT 'user', + status VARCHAR(20) NOT NULL DEFAULT 'active', + created_at DATETIME NOT NULL, + updated_at DATETIME NOT NULL, + last_login DATETIME + );` + + _, err := db.Exec(createTableSQL) + return err +} + +// AddUser 添加新用户 +func AddUser(user User) (*User, error) { + // 使用全局数据库连接 + conn := GetSqliteDB() + if conn == nil { + return nil, ErrDbNotInit + } + + insertSQL := ` + INSERT INTO sc_user (username, email, password_hash, role, status, created_at, updated_at, last_login) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + ` + + result, err := conn.Exec(insertSQL, + user.Username, user.Email, user.PasswordHash, user.Role, + user.Status, user.CreatedAt, user.UpdatedAt, user.LastLogin, + ) + if err != nil { + return nil, err + } + + // 获取插入的ID + id, err := result.LastInsertId() + if err != nil { + return nil, err + } + + // 设置ID并返回 + user.ID = int(id) + return &user, nil +} + +// GetUserByUsername 根据用户名获取用户 +func GetUserByUsername(username string) (*User, error) { + conn := GetSqliteDB() + if conn == nil { + return nil, ErrDbNotInit + } + + querySQL := ` + SELECT id, username, email, password_hash, role, status, created_at, updated_at, last_login + FROM sc_user WHERE username = ? + ` + + var user User + err := conn.QueryRow(querySQL, username).Scan( + &user.ID, &user.Username, &user.Email, &user.PasswordHash, + &user.Role, &user.Status, &user.CreatedAt, &user.UpdatedAt, &user.LastLogin, + ) + + if err != nil { + return nil, err + } + + return &user, nil +} + +// GetUserByEmail 根据邮箱获取用户 +func GetUserByEmail(email string) (*User, error) { + conn := GetSqliteDB() + if conn == nil { + return nil, ErrDbNotInit + } + + querySQL := ` + SELECT id, username, email, password_hash, role, status, created_at, updated_at, last_login + FROM sc_user WHERE email = ? + ` + + var user User + err := conn.QueryRow(querySQL, email).Scan( + &user.ID, &user.Username, &user.Email, &user.PasswordHash, + &user.Role, &user.Status, &user.CreatedAt, &user.UpdatedAt, &user.LastLogin, + ) + + if err != nil { + return nil, err + } + + return &user, nil +} + +// CheckUsernameExists 检查用户名是否存在 +func CheckUsernameExists(username string) (bool, error) { + conn := GetSqliteDB() + if conn == nil { + return false, ErrDbNotInit + } + + querySQL := "SELECT COUNT(*) FROM sc_user WHERE username = ?" + var count int + err := conn.QueryRow(querySQL, username).Scan(&count) + if err != nil { + return false, err + } + + return count > 0, nil +} + +// CheckEmailExists 检查邮箱是否存在 +func CheckEmailExists(email string) (bool, error) { + conn := GetSqliteDB() + if conn == nil { + return false, ErrDbNotInit + } + + querySQL := "SELECT COUNT(*) FROM sc_user WHERE email = ?" + var count int + err := conn.QueryRow(querySQL, email).Scan(&count) + if err != nil { + return false, err + } + + return count > 0, nil +} + +// UpdateUserPassword 更新用户密码 +func UpdateUserPassword(userID int, passwordHash string, updatedAt time.Time) error { + conn := GetSqliteDB() + if conn == nil { + return ErrDbNotInit + } + + updateSQL := "UPDATE sc_user SET password_hash = ?, updated_at = ? WHERE id = ?" + _, err := conn.Exec(updateSQL, passwordHash, updatedAt, userID) + return err +} + +// UpdateUserLastLogin 更新用户最后登录时间 +func UpdateUserLastLogin(userID int) error { + conn := GetSqliteDB() + if conn == nil { + return ErrDbNotInit + } + + updateSQL := "UPDATE sc_user SET last_login = ? WHERE id = ?" + _, err := conn.Exec(updateSQL, time.Now(), userID) + return err +} diff --git a/aufs/db/sqliteDb.go b/aufs/db/sqliteDb.go index da4f9ab..96c3359 100644 --- a/aufs/db/sqliteDb.go +++ b/aufs/db/sqliteDb.go @@ -2,6 +2,7 @@ package db import ( "fmt" + "database/sql" // 导入包,导入前缀为下划线,则init函数被执行,然后注册驱动。 "github.com/jmoiron/sqlx" @@ -11,6 +12,9 @@ import ( var db *sqlx.DB var err error +// 数据库错误常量 +var ErrDbNotInit = fmt.Errorf("database not initialized") + func Init() { // fmt.Printf("hey,I am initilize function in SqliteDb\n")s // @@ -24,6 +28,10 @@ func Init() { // defer db.Close() // connectDB() + // 创建必要的表 + CreateTable() + // 创建用户表 + createUserTableIfNotExists() } // 连接数据库 @@ -37,6 +45,31 @@ func connectDB() { } } +// GetSqliteDB 获取数据库连接 +func GetSqliteDB() *sql.DB { + if db == nil { + return nil + } + return db.DB +} + +// createUserTableIfNotExists 创建用户表(如果不存在) +func createUserTableIfNotExists() { + sqlDB := GetSqliteDB() + if sqlDB == nil { + fmt.Printf("Failed to get database connection for user table creation\n") + return + } + + err := CreateUserTable(sqlDB) + if err != nil { + fmt.Printf("Failed to create user table: %v\n", err) + return + } + + fmt.Printf("User table created successfully\n") +} + // 创建数据库表 func CreateTable() { // 建表语句