直播:后台 JWT 推流、前台画中画;WebRTC 服务与 Nginx WebSocket 代理
Made-with: Cursor
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
@@ -34,6 +35,37 @@ type Claims struct {
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// ParseClaimsFromTokenString 解析 Authorization Bearer 或裸 JWT;失败返回 false
|
||||
func ParseClaimsFromTokenString(tokenStr string) (*Claims, bool) {
|
||||
tokenStr = strings.TrimSpace(tokenStr)
|
||||
if len(tokenStr) > 7 && strings.EqualFold(tokenStr[:7], "bearer ") {
|
||||
tokenStr = strings.TrimSpace(tokenStr[7:])
|
||||
}
|
||||
if tokenStr == "" {
|
||||
return nil, false
|
||||
}
|
||||
var claims Claims
|
||||
token, err := jwt.ParseWithClaims(tokenStr, &claims, func(t *jwt.Token) (interface{}, error) {
|
||||
return []byte(jwtSecret), nil
|
||||
})
|
||||
if err != nil || !token.Valid {
|
||||
return nil, false
|
||||
}
|
||||
return &claims, true
|
||||
}
|
||||
|
||||
// LivePublishAllowed 仅允许已登录后台账号发起 WebRTC 推流(与 AuthRequired 身份范围一致)
|
||||
func LivePublishAllowed(tokenStr string) bool {
|
||||
claims, ok := ParseClaimsFromTokenString(tokenStr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if claims.RoleID != models.RoleIDSuperAdmin && !(claims.RoleID == models.RoleIDSuperUser && claims.Role == "admin") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Login 后台登录,仅 role_id=9527 超级管理员可登录
|
||||
func Login(c *gin.Context) {
|
||||
var input LoginInput
|
||||
@@ -122,25 +154,13 @@ func AuthRequired() gin.HandlerFunc {
|
||||
if tokenStr == "" {
|
||||
tokenStr = c.Query("token")
|
||||
}
|
||||
if len(tokenStr) > 7 && tokenStr[:7] == "Bearer " {
|
||||
tokenStr = tokenStr[7:]
|
||||
}
|
||||
if tokenStr == "" {
|
||||
claims, ok := ParseClaimsFromTokenString(tokenStr)
|
||||
if !ok {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
var claims Claims
|
||||
token, err := jwt.ParseWithClaims(tokenStr, &claims, func(t *jwt.Token) (interface{}, error) {
|
||||
return []byte(jwtSecret), nil
|
||||
})
|
||||
if err != nil || !token.Valid {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "登录已过期,请重新登录"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 仅超级管理员或超级用户(role_id=0, role=admin)可访问后台
|
||||
if claims.RoleID != models.RoleIDSuperAdmin && !(claims.RoleID == models.RoleIDSuperUser && claims.Role == "admin") {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "无后台访问权限"})
|
||||
@@ -164,25 +184,13 @@ func SuperUserAuthRequired() gin.HandlerFunc {
|
||||
if tokenStr == "" {
|
||||
tokenStr = c.Query("token")
|
||||
}
|
||||
if len(tokenStr) > 7 && tokenStr[:7] == "Bearer " {
|
||||
tokenStr = tokenStr[7:]
|
||||
}
|
||||
if tokenStr == "" {
|
||||
claims, ok := ParseClaimsFromTokenString(tokenStr)
|
||||
if !ok {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
var claims Claims
|
||||
token, err := jwt.ParseWithClaims(tokenStr, &claims, func(t *jwt.Token) (interface{}, error) {
|
||||
return []byte(jwtSecret), nil
|
||||
})
|
||||
if err != nil || !token.Valid {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "登录已过期,请重新登录"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 仅 role_id=9527 且 role=admin 可配置短信平台
|
||||
if claims.RoleID != models.RoleIDSuperAdmin || claims.Role != "admin" {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "仅超级管理员可配置短信平台"})
|
||||
|
||||
@@ -204,7 +204,9 @@ func defaultHomepageData() models.HomepageData {
|
||||
{Title: "量子同步", Desc: "跨维度数据同步技术,您的数据在多宇宙中保持一致"},
|
||||
{Title: "星际防护", Desc: "来自未来的安全加密协议,守护您的数字资产安全"},
|
||||
},
|
||||
FooterText: "© 2024 宇恒一号 · 成都宇信达智能科技有限公司",
|
||||
FooterText: "© 2024 宇恒一号 · 成都宇信达智能科技有限公司",
|
||||
LiveRoomURL: "",
|
||||
LiveRoomTitle: "视频直播",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user