基础框架先行,编译器已无报错,项目正式创建
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var jwtSecret = []byte("frpc-console-secret-key-2024")
|
||||
|
||||
type Claims struct {
|
||||
Username string `json:"username"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func GenerateJWT(username string) (string, error) {
|
||||
claims := Claims{
|
||||
Username: username,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
},
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(jwtSecret)
|
||||
}
|
||||
|
||||
func ParseJWT(tokenString string) (*Claims, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return jwtSecret, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
return nil, errors.New("invalid token")
|
||||
}
|
||||
|
||||
// 密码复杂度验证:至少3个大写 + 8个数字 + 1个特殊字符
|
||||
func ValidatePassword(pwd string) bool {
|
||||
var upper, digit, special int
|
||||
for _, ch := range pwd {
|
||||
if ch >= 'A' && ch <= 'Z' {
|
||||
upper++
|
||||
}
|
||||
if ch >= '0' && ch <= '9' {
|
||||
digit++
|
||||
}
|
||||
if strings.ContainsAny(string(ch), "!@#$%^&*()_+-=[]{}|;:,.<>?") {
|
||||
special++
|
||||
}
|
||||
}
|
||||
return upper >= 3 && digit >= 8 && special >= 1 && len(pwd) >= 12
|
||||
}
|
||||
|
||||
// 首次启动强制设置管理员账户
|
||||
func InitAdminUser() {
|
||||
count, err := CountUsers()
|
||||
if err != nil {
|
||||
log.Fatal("❌ 检查用户表失败:", err)
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
log.Println("✅ 已存在管理员账户,跳过初始化")
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("⚠️ 首次启动,请设置管理员账户")
|
||||
log.Print("用户名: ")
|
||||
var username string
|
||||
fmt.Scanln(&username)
|
||||
|
||||
if username == "" {
|
||||
username = "admin"
|
||||
}
|
||||
|
||||
for {
|
||||
log.Print("密码 (至少3个大写+8个数字+1个特殊字符): ")
|
||||
var password string
|
||||
fmt.Scanln(&password)
|
||||
|
||||
if ValidatePassword(password) {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
log.Println("❌ 密码加密失败:", err)
|
||||
continue
|
||||
}
|
||||
err = CreateUser(username, string(hash))
|
||||
if err != nil {
|
||||
log.Println("❌ 创建用户失败:", err)
|
||||
continue
|
||||
}
|
||||
log.Println("✅ 管理员账户创建成功!")
|
||||
break
|
||||
} else {
|
||||
log.Println("❌ 密码不符合复杂度要求,请重新输入")
|
||||
log.Println(" 要求: 至少3个大写字母 + 8个数字 + 1个特殊字符")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JWT 认证中间件
|
||||
func AuthMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "msg": "未提供认证令牌"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
// 格式 "Bearer <token>"
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "msg": "认证令牌格式错误"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
tokenString := parts[1]
|
||||
claims, err := ParseJWT(tokenString)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "msg": "无效的认证令牌"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
// 将用户名存入上下文,方便后续使用
|
||||
c.Set("username", claims.Username)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user