4 changed files with 485 additions and 0 deletions
@ -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 |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
Loading…
Reference in new issue