-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: finish task #15
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,97 @@ | ||||||||||||||||||||||||||||||||||||||||
package main | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||||||||||||||||
"encoding/base64" | ||||||||||||||||||||||||||||||||||||||||
"github.com/gin-gonic/gin" | ||||||||||||||||||||||||||||||||||||||||
"gorm.io/gorm" | ||||||||||||||||||||||||||||||||||||||||
"log" | ||||||||||||||||||||||||||||||||||||||||
"math/rand" | ||||||||||||||||||||||||||||||||||||||||
"net/http" | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 用户结构体 | ||||||||||||||||||||||||||||||||||||||||
type User struct { | ||||||||||||||||||||||||||||||||||||||||
gorm.Model | ||||||||||||||||||||||||||||||||||||||||
Profile Profile // 与 Profile 一对一关联 | ||||||||||||||||||||||||||||||||||||||||
Blogs []Blog `gorm:"foreignKey:UserId"` // 与 Blog 一对多关联 | ||||||||||||||||||||||||||||||||||||||||
Replies []Reply `gorm:"foreignKey:UserId"` // 与 Reply 一对多关联 | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
ID uint // 用户ID | ||||||||||||||||||||||||||||||||||||||||
Username string `json:"username"` // 用户名 | ||||||||||||||||||||||||||||||||||||||||
Password string `json:"password"` // 密码 | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+13
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the duplicate The Apply this diff to remove the duplicate type User struct {
gorm.Model
Profile Profile // 与 Profile 一对一关联
Blogs []Blog `gorm:"foreignKey:UserId"` // 与 Blog 一对多关联
Replies []Reply `gorm:"foreignKey:UserId"` // 与 Reply 一对多关联
- ID uint // 用户ID
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 登录功能 | ||||||||||||||||||||||||||||||||||||||||
func login(c *gin.Context) { | ||||||||||||||||||||||||||||||||||||||||
var user User | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 解析 JSON 请求 | ||||||||||||||||||||||||||||||||||||||||
if err := c.ShouldBindJSON(&user); err != nil { | ||||||||||||||||||||||||||||||||||||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) // 返回错误信息 | ||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 确认用户是否存在并且密码是否正确 | ||||||||||||||||||||||||||||||||||||||||
UserExists := checkUserExists(user.Username, user.Password) | ||||||||||||||||||||||||||||||||||||||||
if UserExists { | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+35
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improve error handling in The Modify the import (
"errors"
"gorm.io/gorm"
)
func checkUserExists(username string, password string) bool {
var user User
err := db.Where("username = ?", username).First(&user).Error // 查询用户
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// User not found
return false
}
log.Println("Error checking user existence:", err) // 打印错误
return false
}
// Compare the hashed password
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err != nil {
// Password does not match
return false
}
// Password matches
return true
} |
||||||||||||||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"message": "登陆成功!"}) // 登录成功 | ||||||||||||||||||||||||||||||||||||||||
c.SetCookie("username", base64.StdEncoding.EncodeToString([]byte(user.Username)), 3600, "/", "localhost", false, true) // 设置 Cookie | ||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid storing the username in plaintext cookies Storing the username in a cookie, even if base64 encoded, can expose sensitive user information. Base64 encoding is not encryption and can be easily decoded. Consider using secure session tokens or JWTs for session management. Implement session management using secure tokens. For example, generate a signed JWT token upon successful login: import "github.com/dgrijalva/jwt-go"
// Create the token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"username": user.Username,
"exp": time.Now().Add(time.Hour * 1).Unix(),
})
// Sign and get the complete encoded token as a string
tokenString, err := token.SignedString([]byte("your-secret-key"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
return
}
// Set the token as a cookie
c.SetCookie("token", tokenString, 3600, "/", "localhost", false, true) Ensure to validate the token on subsequent requests. |
||||||||||||||||||||||||||||||||||||||||
log.Println("Cookie set:", base64.StdEncoding.EncodeToString([]byte(user.Username))) | ||||||||||||||||||||||||||||||||||||||||
user.ID = uint(rand.Uint32()) // 随机生成用户ID(此处可能需要修改) | ||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not assign random user IDs during login Assigning a random user ID during login ( Apply this diff to remove the random ID assignment: log.Println("Cookie set:", base64.StdEncoding.EncodeToString([]byte(user.Username)))
-user.ID = uint(rand.Uint32()) // 随机生成用户ID(此处可能需要修改)
return
|
||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"message": "用户未注册,请先注册!"}) // 用户未注册 | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 注册功能 | ||||||||||||||||||||||||||||||||||||||||
func register(c *gin.Context) { | ||||||||||||||||||||||||||||||||||||||||
var user User | ||||||||||||||||||||||||||||||||||||||||
if err := c.ShouldBindJSON(&user); err != nil { | ||||||||||||||||||||||||||||||||||||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) // 返回错误信息 | ||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 检查用户是否已注册 | ||||||||||||||||||||||||||||||||||||||||
UserExists := checkUserExists(user.Username, user.Password) | ||||||||||||||||||||||||||||||||||||||||
exists := checkUsernameExists(user.Username) | ||||||||||||||||||||||||||||||||||||||||
if UserExists { | ||||||||||||||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"message": "该账户已注册,请转至登陆界面"}) // 已注册提示 | ||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
if exists { | ||||||||||||||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"message": "该用户名已存在,请更换"}) // 用户名已存在 | ||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+55
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simplify user existence checks during registration In the Apply this diff to simplify the checks: // 检查用户是否已注册
-UserExists := checkUserExists(user.Username, user.Password)
exists := checkUsernameExists(user.Username)
-if UserExists {
- c.JSON(http.StatusOK, gin.H{"message": "该账户已注册,请转至登陆界面"}) // 已注册提示
- return
-}
if exists {
c.JSON(http.StatusOK, gin.H{"message": "该用户名已存在,请更换"}) // 用户名已存在
return
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
// 创建用户记录 | ||||||||||||||||||||||||||||||||||||||||
if err := db.Create(&user).Error; err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Println("Error creating user:", err) // 打印错误 | ||||||||||||||||||||||||||||||||||||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) // 返回错误信息 | ||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
c.JSON(http.StatusCreated, gin.H{"message": "成功注册!"}) // 注册成功 | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 检查用户是否存在 | ||||||||||||||||||||||||||||||||||||||||
func checkUserExists(username string, password string) bool { | ||||||||||||||||||||||||||||||||||||||||
var user User | ||||||||||||||||||||||||||||||||||||||||
result := db.Where("username = ?", username).First(&user) // 查询用户 | ||||||||||||||||||||||||||||||||||||||||
if result.Error != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Println("Error checking user existence:", result.Error) // 打印错误 | ||||||||||||||||||||||||||||||||||||||||
return false | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 返回用户名和密码是否匹配 | ||||||||||||||||||||||||||||||||||||||||
return user.Username == username && user.Password == password | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+76
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle user not found error correctly in In Modify the function to handle func checkUserExists(username string, password string) bool {
var user User
err := db.Where("username = ?", username).First(&user).Error // 查询用户
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// User not found
return false
}
log.Println("Error checking user existence:", err) // 打印错误
return false
}
// Compare the hashed password
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err != nil {
// Password does not match
return false
}
// Password matches
return true
} |
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// 检查用户名是否已存在 | ||||||||||||||||||||||||||||||||||||||||
func checkUsernameExists(username string) bool { | ||||||||||||||||||||||||||||||||||||||||
var user User | ||||||||||||||||||||||||||||||||||||||||
result := db.Where("username = ?", username).First(&user) // 查询用户 | ||||||||||||||||||||||||||||||||||||||||
if result.Error != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Println("Error checking user existence:", result.Error) // 打印错误 | ||||||||||||||||||||||||||||||||||||||||
return false | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
return user.Username == username | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+91
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct the return logic in The function Modify the function to handle func checkUsernameExists(username string) bool {
var user User
err := db.Where("username = ?", username).First(&user).Error // 查询用户
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// User not found
return false
}
log.Println("Error checking user existence:", err) // 打印错误
return false
}
return true
} |
||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,184 @@ | ||||||||||||||||||||||||||||
package main | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||||
"encoding/base64" | ||||||||||||||||||||||||||||
"fmt" | ||||||||||||||||||||||||||||
"github.com/gin-gonic/gin" | ||||||||||||||||||||||||||||
"gorm.io/gorm" | ||||||||||||||||||||||||||||
"math/rand" | ||||||||||||||||||||||||||||
"net/http" | ||||||||||||||||||||||||||||
"time" | ||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
type Blog struct { | ||||||||||||||||||||||||||||
gorm.Model | ||||||||||||||||||||||||||||
//User | ||||||||||||||||||||||||||||
UserId uint | ||||||||||||||||||||||||||||
//一对多reply | ||||||||||||||||||||||||||||
Replies []Reply `gorm:"foreignKey:BlogID"` | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
ID uint | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove redundant The Apply this diff to remove the redundant type Blog struct {
gorm.Model
//User
UserId uint
//一对多reply
Replies []Reply `gorm:"foreignKey:BlogID"`
- ID uint
Time string
Content string `json:"content"`
Title string `json:"title"`
Author string `json:"author"`
Type string `json:"type"`
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
Time string | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider using Since Apply this diff to remove the custom type Blog struct {
gorm.Model
//User
UserId uint
//一对多reply
Replies []Reply `gorm:"foreignKey:BlogID"`
- Time string
Content string `json:"content"`
Title string `json:"title"`
Author string `json:"author"`
Type string `json:"type"`
}
|
||||||||||||||||||||||||||||
Content string `json:"content"` | ||||||||||||||||||||||||||||
Title string `json:"title"` | ||||||||||||||||||||||||||||
Author string `json:"author"` | ||||||||||||||||||||||||||||
Type string `json:"type"` | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
type Reply struct { | ||||||||||||||||||||||||||||
gorm.Model | ||||||||||||||||||||||||||||
//User | ||||||||||||||||||||||||||||
UserId uint | ||||||||||||||||||||||||||||
//blog | ||||||||||||||||||||||||||||
BlogID uint `json:"BlogID"` | ||||||||||||||||||||||||||||
Body string `json:"body"` | ||||||||||||||||||||||||||||
Who string `json:"who"` | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 显示我的提问与回复 | ||||||||||||||||||||||||||||
func mine(c *gin.Context) { | ||||||||||||||||||||||||||||
cookieValue, err := loadCookie(c) | ||||||||||||||||||||||||||||
userId, _ := base64.StdEncoding.DecodeString(cookieValue) | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle error returned by The Update the code to handle the error: -cookieValue, err := loadCookie(c)
-userId, _ := base64.StdEncoding.DecodeString(cookieValue)
+cookieValue, err := loadCookie(c)
+if err != nil {
+ c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
+ return
+}
+userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
+if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
+ return
+}
+userId := string(userIdBytes)
|
||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
//查找user下的所有blog和blog下的所有reply | ||||||||||||||||||||||||||||
var user User | ||||||||||||||||||||||||||||
// 先通过 username 查询 User | ||||||||||||||||||||||||||||
if err := db.Where("username = ?", userId).First(&user).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
// 通过预加载获取该用户的所有 Blogs 和对应的 Replies | ||||||||||||||||||||||||||||
if err := db.Preload("Blogs.Replies").First(&user, user.ID).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusNotFound, gin.H{"error": "Blogs not found"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"user": user}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 显示其他人的问题 | ||||||||||||||||||||||||||||
func others(c *gin.Context) { | ||||||||||||||||||||||||||||
var blogs []Blog | ||||||||||||||||||||||||||||
// 预加载所有 Blogs 及其对应的 Replies | ||||||||||||||||||||||||||||
if err := db.Preload("Replies").Find(&blogs).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve blogs"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"blogs": blogs}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 创建我的新问题 | ||||||||||||||||||||||||||||
func mineNews(c *gin.Context) { | ||||||||||||||||||||||||||||
cookieValue, err := loadCookie(c) | ||||||||||||||||||||||||||||
userId, _ := base64.StdEncoding.DecodeString(cookieValue) | ||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
var blogs Blog | ||||||||||||||||||||||||||||
blogs.ID = uint(rand.Uint32()) | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not manually assign GORM automatically handles the assignment of Remove the manual ID assignment: -blogs.ID = uint(rand.Uint32()) GORM will automatically assign a unique ID when you create the record. 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
blogs.Time = time.Now().Format("2006-01-02 15:04:05") | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Utilize Similar to the previous suggestion, rely on Remove the manual time assignment and the |
||||||||||||||||||||||||||||
if err := c.ShouldBind(&blogs); err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+88
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Handle overlapping fields when binding JSON data Using Adjust the code to bind the JSON into a separate struct and then map the fields: type BlogInput struct {
Content string `json:"content"`
Title string `json:"title"`
Author string `json:"author"`
Type string `json:"type"`
}
var input BlogInput
if err := c.ShouldBind(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
blog := Blog{
Content: input.Content,
Title: input.Title,
Author: input.Author,
Type: input.Type,
UserId: user.ID,
}
if err := db.Create(&blog).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create blog"})
return
} This approach avoids unintended overwrites and makes the code clearer. |
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
var user User | ||||||||||||||||||||||||||||
if err := db.Where("username = ?", string(userId)).First(&user).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
//键赋值 | ||||||||||||||||||||||||||||
blogs.UserId = user.ID | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if err := db.Create(&blogs).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"blogs": blogs}) | ||||||||||||||||||||||||||||
fmt.Println("成功发布问题") | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func reply(c *gin.Context) { | ||||||||||||||||||||||||||||
cookieValue, err := loadCookie(c) | ||||||||||||||||||||||||||||
userId, _ := base64.StdEncoding.DecodeString(cookieValue) | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle error from As previously noted, handle the error returned by Update the code to handle the error: -userId, _ := base64.StdEncoding.DecodeString(cookieValue)
+userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
+if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
+ return
+}
+userId := string(userIdBytes) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+110
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle missing return statements after sending error responses In the Add return statements after sending error responses: if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
+ return
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 检查用户是否存在 | ||||||||||||||||||||||||||||
var user User | ||||||||||||||||||||||||||||
if err := db.Where("username = ?", userId).First(&user).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
//创建回复 | ||||||||||||||||||||||||||||
var reply Reply | ||||||||||||||||||||||||||||
if err := c.ShouldBind(&reply); err != nil { | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+126
to
+129
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add return statement after handling binding error After sending an error response due to binding failure, you should return to prevent further execution. Add a return statement: if err := c.ShouldBind(&reply); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
//键赋值 | ||||||||||||||||||||||||||||
reply.UserId = user.ID | ||||||||||||||||||||||||||||
//上传回复 | ||||||||||||||||||||||||||||
if err := db.Create(&reply).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create reply"}) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+134
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add return statement after handling database error Similarly, after handling the error from if err := db.Create(&reply).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create reply"})
+ return
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"reply": reply}) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func blogEdit(c *gin.Context) { | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
var blog Blog | ||||||||||||||||||||||||||||
blogID := c.Param("id") // 获取 URL 中的博客 ID | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 查找博客 | ||||||||||||||||||||||||||||
if err := db.First(&blog, blogID).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 绑定更新数据 | ||||||||||||||||||||||||||||
if err := c.ShouldBind(&blog); err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+152
to
+155
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid overwriting critical fields during update Using Define an input struct: type BlogUpdateInput struct {
Title string `json:"title"`
Content string `json:"content"`
Type string `json:"type"`
} Update the binding: var input BlogUpdateInput
if err := c.ShouldBind(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
blog.Title = input.Title
blog.Content = input.Content
blog.Type = input.Type |
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 更新博客 | ||||||||||||||||||||||||||||
if err := db.Save(&blog).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update blog"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"blog": blog}) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+140
to
+164
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Authorize users before allowing blog edits Currently, any user can edit any blog post. Implement authorization to ensure that only the owner of the blog can edit it. [security] Consider adding a check to verify that the requesting user is the owner: cookieValue, err := loadCookie(c)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}
userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
return
}
userId := string(userIdBytes)
if blog.UserId != userId {
c.JSON(http.StatusForbidden, gin.H{"error": "You are not allowed to edit this blog"})
return
} This ensures that only the author can modify their blog post. |
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
func blogDelete(c *gin.Context) { | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
blogID := c.Param("id") // 获取 URL 中的博客 ID | ||||||||||||||||||||||||||||
var blog Blog | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 查找博客 | ||||||||||||||||||||||||||||
if err := db.First(&blog, blogID).Error; err != nil { | ||||||||||||||||||||||||||||
Comment on lines
+168
to
+172
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate and parse
Convert id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid blog ID"})
return
}
if err := db.First(&blog, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"})
return
} Remember to import |
||||||||||||||||||||||||||||
c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// 删除博客 | ||||||||||||||||||||||||||||
if err := db.Delete(&blog).Error; err != nil { | ||||||||||||||||||||||||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete blog"}) | ||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
c.JSON(http.StatusOK, gin.H{"message": "Blog deleted successfully"}) | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
Comment on lines
+166
to
+184
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Authorize users before allowing blog deletion Similar to editing, ensure that only the owner of the blog can delete it. [security] Add authorization check: // Get the user's ID from the cookie
cookieValue, err := loadCookie(c)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}
userIdBytes, err := base64.StdEncoding.DecodeString(cookieValue)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cookie encoding"})
return
}
userId := string(userIdBytes)
if blog.UserId != userId {
c.JSON(http.StatusForbidden, gin.H{"error": "You are not allowed to delete this blog"})
return
} Ensuring proper authorization prevents unauthorized access and modification. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
module myproject | ||
|
||
go 1.23.1 | ||
|
||
require ( | ||
filippo.io/edwards25519 v1.1.0 // indirect | ||
github.com/bytedance/sonic v1.12.3 // indirect | ||
github.com/bytedance/sonic/loader v0.2.0 // indirect | ||
github.com/cloudwego/base64x v0.1.4 // indirect | ||
github.com/cloudwego/iasm v0.2.0 // indirect | ||
github.com/gabriel-vasile/mimetype v1.4.5 // indirect | ||
github.com/gin-contrib/sse v0.1.0 // indirect | ||
github.com/gin-gonic/gin v1.10.0 // indirect | ||
github.com/go-playground/locales v0.14.1 // indirect | ||
github.com/go-playground/universal-translator v0.18.1 // indirect | ||
github.com/go-playground/validator/v10 v10.22.1 // indirect | ||
github.com/go-sql-driver/mysql v1.8.1 // indirect | ||
github.com/goccy/go-json v0.10.3 // indirect | ||
github.com/jinzhu/inflection v1.0.0 // indirect | ||
github.com/jinzhu/now v1.1.5 // indirect | ||
github.com/json-iterator/go v1.1.12 // indirect | ||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect | ||
github.com/leodido/go-urn v1.4.0 // indirect | ||
github.com/mattn/go-isatty v0.0.20 // indirect | ||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | ||
github.com/modern-go/reflect2 v1.0.2 // indirect | ||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect | ||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | ||
github.com/ugorji/go/codec v1.2.12 // indirect | ||
golang.org/x/arch v0.10.0 // indirect | ||
golang.org/x/crypto v0.27.0 // indirect | ||
golang.org/x/net v0.29.0 // indirect | ||
golang.org/x/sys v0.25.0 // indirect | ||
golang.org/x/text v0.18.0 // indirect | ||
google.golang.org/protobuf v1.34.2 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
gorm.io/driver/mysql v1.5.7 // indirect | ||
gorm.io/gorm v1.25.12 // indirect | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hash passwords before storing them
Storing passwords in plain text is a significant security risk. It's essential to hash passwords using a secure hashing algorithm (e.g., bcrypt) before saving them to the database.
You can use the
golang.org/x/crypto/bcrypt
package to hash and compare passwords. Here's how you can modify your code:When registering a new user:
When checking the password during login:
Please update the relevant functions to incorporate password hashing and comparison.