diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ad1a919 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# 第一阶段:使用最新Go版本构建 +FROM docker.1ms.run/golang:1.24 AS builder + +WORKDIR /app + +ENV GOPROXY=https://goproxy.cn,direct + + +# 复制go.mod和go.sum以缓存依赖 +COPY go.mod go.sum ./ +RUN go mod download + +# 复制源代码并构建 +COPY . . +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags="-s -w" -o videoplayer . + +# 第二阶段:生产环境(最小化镜像) +FROM scratch + +# 复制配置文件 +COPY --from=builder /app/saw-ai.conf /home/saw/saw-ai.conf + +# 复制二进制文件 +COPY --from=builder /app/videoplayer /home/videoplayer/videoplayer + +# 设置工作目录 +WORKDIR /home/videoplayer + +# 暴露端口 +EXPOSE 8083 + +# 运行应用 +CMD ["./videoplayer"] \ No newline at end of file diff --git a/main.go b/main.go index f2e2886..a112293 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "errors" "fmt" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt" @@ -100,29 +101,23 @@ func JWTAuthMiddleware() gin.HandlerFunc { } // 从请求头中获取 JWT 令牌 tokenString := c.Request.Header.Get("token") - //请求方式为get时,从url中获取token if tokenString == "" { tokenString = c.Query("token") } - //如果请求为login或register,则不需要验证token - //for k, _ := range proto.Url_map { - // if strings.Contains(c.Request.URL.Path, k) { - // c.Next() - // return - // } - //} - if proto.Url_map[c.Request.URL.Path] == true { //查看是否在不需要token的url中 - c.Next() - return + for k, _ := range proto.Url_map { + if strings.Contains(c.Request.URL.Path, k) { + log.Println("need not check token:", c.Request.URL.Path) + c.Next() + return + } } + //if proto.Url_map[c.Request.URL.Path] == true { //查看是否在不需要token的url中 + // c.Next() + // return + //} if tokenString == "" { - //c.AbortWithStatus(200) - c.JSON(200, gin.H{ - "message": "Unauthorized", - "error": "token is empty", - "code": proto.TokenIsNull, - }) + c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "unauthorized", "error": "token is empty", "code": proto.TokenIsNull}) return } if proto.Config.TOKEN_USE_REDIS { @@ -132,7 +127,6 @@ func JWTAuthMiddleware() gin.HandlerFunc { return } } - //查看token是否在超级token中 if worker.IsContainSet("super_permission_tokens", tokenString) { sId := c.Request.Header.Get("super_id") @@ -147,40 +141,52 @@ func JWTAuthMiddleware() gin.HandlerFunc { idFloat64 := float64(id) //查看s_id类型 c.Set("id", idFloat64) + c.Set("user_id", id) c.Next() return } // 使用加密secret 解析 JWT 令牌 - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + //token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + // return proto.SigningKey, nil + //}) + token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) { + // 验证签名算法 + if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, jwt.ErrSignatureInvalid + } return proto.SigningKey, nil }) - - // 验证令牌 - if err != nil || !token.Valid { - c.AbortWithStatusJSON(http.StatusOK, gin.H{ - "message": "NOT_LOGIN", - "error": "Invalid token", - "code": proto.TokenExpired, - }) - return + // 错误处理 + if err != nil { + var ve *jwt.ValidationError + if errors.As(err, &ve) { + switch { + case ve.Errors&jwt.ValidationErrorMalformed != 0: + c.AbortWithStatusJSON(http.StatusOK, gin.H{"error": "Malformed token:" + err.Error(), "code": proto.TokenInvalid}) + case ve.Errors&jwt.ValidationErrorExpired != 0: + c.AbortWithStatusJSON(http.StatusOK, gin.H{"error": "Token expired:" + err.Error(), "code": proto.TokenExpired}) + case ve.Errors&jwt.ValidationErrorNotValidYet != 0: + c.AbortWithStatusJSON(http.StatusOK, gin.H{"error": "Token not active yet:" + err.Error(), "code": proto.TokenInvalid}) + default: + c.AbortWithStatusJSON(http.StatusOK, gin.H{"error": "Invalid token:" + err.Error(), "code": proto.TokenInvalid}) + } + return + } } // 将用户信息添加到上下文中 - c.Set("id", token.Claims.(jwt.MapClaims)["id"]) - c.Set("username", token.Claims.(jwt.MapClaims)["username"]) + id := token.Claims.(jwt.MapClaims)["id"] + c.Set("id", id) + c.Set("user_id", int(id.(float64))) - if UserFuncIntercept(int(token.Claims.(jwt.MapClaims)["id"].(float64)), c.Request.URL.Path) { - c.AbortWithStatusJSON(http.StatusOK, gin.H{ - "message": "no function permission", - "error": "no permission", - "code": proto.NoPermission, - }) + if UserFuncIntercept(int(id.(float64)), c.Request.URL.Path) { + c.AbortWithStatusJSON(http.StatusOK, gin.H{"message": "unauthorized", "error": "no function permission", "code": proto.NoPermission}) return } - // 继续处理请求 c.Next() + //log.Println("JWT token is valid, user ID:", token.Claims.(jwt.MapClaims)["id"], " path:", c.Request.URL.Path) } } diff --git a/vp.conf b/vp.conf index 33869ad..3ccb203 100644 --- a/vp.conf +++ b/vp.conf @@ -1,15 +1,21 @@ { "db":0, - "mysql_dsn":"video_t2:2t2SKHmWEYj2xFKF@tcp(127.0.0.1:3306)/video_t2?charset=utf8mb4&parseTime=True&loc=Local", + "mysql_dsn":"vp-db:ZcxsP7s7kaBxxDPc@tcp(tx.ljsea.top:3306)/vp-db?charset=utf8mb4&parseTime=True&loc=Local", "pg_dsn":"host=localhost user=video_t2 dbname=video_t2 password=2t2SKHmWEYj2xFKF port=5432 TimeZone=Asia/Shanghai", - "redis_addr":"127.0.0.1:6379", + "redis_addr":"host.docker.internal:6379", "redis_db":2, "redis_user_pw":true, - "token_use_redis":true, + "token_use_redis":false, "redis_password":"lj502138", "token_secret":"mfjurnc_32ndj9dfhj", "cid_base_dir":"/home/lijun/cid/", "file_base_dir":"/home/lijun/file/", - "monitor":false, - "server_port":"8083" + "monitor": true, + "server_port": "8083", + "log_save_days": 3, + "user_type": "slave", + "master_server_domain": "tx.ljsea.top", + "user_sync_time": 0, + "server_name": "home_vp_docker_server", + "monitor_server_token": "627gyf3488h" } \ No newline at end of file