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