Files
web_hgcg_server/web/middleware/auth/http.go
T
rootandClaude Opus 4.7 f8ae5e13dd 代码优化
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-27 17:11:58 +08:00

285 lines
6.3 KiB
Go

package auth
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"strings"
"sync"
"videoweb/pub/common"
"videoweb/pub/common/errors"
"videoweb/pub/common/ipaddr"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/common/utils"
"videoweb/pub/models/mwacc"
"videoweb/pub/models/oplog"
"videoweb/web/webg"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
)
var (
RoleApiMenus = map[int64][]string{} // 角色Api
mutex sync.RWMutex
)
var (
tokener = utils.NewTokenRedis()
)
const (
AccId = "ACC_ID"
roleAuthAdrr = "/web/role/getauth"
)
type APIInfo struct {
Api string
Desc string
}
var (
// 白名单,不需要验证token的api
whiteList = []string{
"/swagger",
"/api/web/file/uploadImg",
"/api/web/file/uploadImgs",
"/api/web/media/videoBody",
"/api/web/media/videoOk",
"/api/web/m3u8",
"/api/web/uploader/m3u8",
"/api/web/enkey",
"/api/web/newenkey",
"/api/web/login/acc",
"/api/web/login/bind",
"/api/web/login/slogin",
"/api/web/stat/media/list",
"/api/web/stat/analytics",
"/api/web/stat/daily/analytics",
"/api/web/sync/video/list",
"/api/web/sync/videocollection/list",
"/api/web/sync/category/list",
"/api/web/sync/creator/list",
"/api/web/sync/tag/list",
"/wbapi",
"/api/web/third/newpaycenter/recharge/callback",
"/api/web/seopush/indexnow/bulk",
}
)
// 读取角色信息
func GetRoleApiMenus(ctx context.Context, accid int64) (roles []string, err error) {
mutex.RLock()
roles, ok := RoleApiMenus[accid]
mutex.RUnlock()
if !ok {
accInfo, dataErr := mwacc.FindOneAccByFilter(nil, bson.M{mwacc.FN.MwAcc.Id: accid})
if dataErr != nil || accInfo.Id == 0 {
return roles, dataErr
}
roleInfo, roleErr := mwacc.FindOneRoleByFilter(ctx, bson.M{mwacc.FN.MwRole.Id: accInfo.RoleId})
if roleErr != nil || roleInfo.Id == 0 {
return roles, roleErr
}
if roleInfo.Name == "超级管理员" {
return nil, nil
}
mutex.Lock()
RoleApiMenus[accid] = roleInfo.ApiMenus
mutex.Unlock()
roles = roleInfo.ApiMenus
}
return
}
// 是否角色api
func HasRoleApi(path string, apis []string) bool {
apimap := make(map[string]struct{})
for _, v := range apis {
apimap[v] = struct{}{}
}
_, ok := apimap[path]
return ok
}
// 角色权限
func handleRoles(ctx *gin.Context) (int, error) {
path := ctx.Request.URL.Path
if strings.HasPrefix(path, roleAuthAdrr) {
return 0, nil
}
accid := ctx.GetInt(AccId)
apis, err := GetRoleApiMenus(ctx, int64(accid))
if err != nil {
return int(errors.RoleErr), err
}
if apis == nil {
return 0, nil
}
has := HasRoleApi(path, apis)
if !has {
return int(errors.RoleErr), srvdef.New(srvdef.RoleErr, (srvdef.RoleErr).Msg(), "")
}
return 0, nil
}
// 验证后台账号IP
func authMwIP(ctx *gin.Context) (int, error) {
cIP := ipaddr.ResolveClientIP(ctx)
accid := ctx.GetInt64(AccId)
accInfo, dataErr := mwacc.FindOneAccByFilter(nil, bson.M{mwacc.FN.MwAcc.Id: accid})
if dataErr != nil || accInfo.Id == 0 {
return int(errors.RoleErr), dataErr
}
if len(accInfo.LimitIP) != 0 {
for _, v := range accInfo.LimitIP {
if v == cIP {
return 0, nil
}
}
return int(errors.LimitIPErr), dataErr
} else {
return int(errors.LimitIPErr), dataErr
}
// return 0, nil
}
// 验证
func Auth(ctx *gin.Context) {
//for test
//ctx.Set(AccId, int64(1000))
//return
// 对指定 group 跳过
if strings.HasPrefix(ctx.Request.URL.Path, "/mdps/mdcom/api/web") {
ctx.Next()
return
}
p := ctx.Request.URL.Path
if strings.Contains(p, "swagger") {
return
}
for _, w := range whiteList {
if strings.HasPrefix(ctx.Request.URL.Path, w) {
return
}
}
if v, ok := common.ApiSetMaps[p]; ok {
fmt.Println(v.IsWhite)
if v.IsWhite {
return
}
}
doToken := func() (int, error) {
checkToken := ctx.Request.Header.Get("Authorization")
// 去掉Bearer,如果有
checkToken = utils.StripBearerPrefixFromTokenString(checkToken)
if checkToken == "" {
return http.StatusUnauthorized, srvdef.New(srvdef.NoToken, (srvdef.NoToken).Msg(), "")
}
has, err := mwacc.CheckToken(ctx, checkToken)
if err != nil {
return http.StatusUnauthorized, err
}
if !has {
return http.StatusUnauthorized, srvdef.New(srvdef.ReLogin, (srvdef.ReLogin).Msg(), "")
}
userId, _, err := utils.ParseUserToken(checkToken, webg.Conf.JwtKey)
if err != nil {
return http.StatusUnauthorized, srvdef.New(srvdef.InvalidToken, (srvdef.InvalidToken).Msg(), "")
}
// log.Info("Auth test", log.Any("checkToken", checkToken), log.Any("userId", userId))
ctx.Set(AccId, userId)
return 0, nil
}
statusCode, err := doToken()
if err != nil || statusCode != 0 {
ctx.AbortWithStatusJSON(statusCode, err)
return
}
roleCode, err := handleRoles(ctx)
if err != nil || roleCode != 0 {
ctx.AbortWithStatusJSON(http.StatusForbidden, err)
}
// authIPCode, err2 := authMwIP(ctx)
// if err2 != nil || authIPCode != 0 {
// ctx.AbortWithStatusJSON(http.StatusForbidden, err)
// }
}
// func userAgentHandler(ctx *gin.Context) {
// userAgent := ctx.Request.Header.Get("User-Agent")
// if userAgent != "" {
// fields := strings.Fields(userAgent)
// curVersion := fields[len(fields)-1]
// if strings.HasPrefix(curVersion, "version:") {
// versionNum := strings.Split(curVersion, ":")[1]
// ctx.Set("VERSION", versionNum)
// } else {
// ctx.Set("VERSION", "")
// }
// }
// if strings.Contains(userAgent, "Android") {
// ctx.Set("SYSTEM", "android")
// }
// if strings.Contains(userAgent, "iPhone") {
// ctx.Set("SYSTEM", "ios")
// }
// // 增加 不签名,不加密 开关
// }
// 操作日志
func OperateLog(ctx *gin.Context) {
desc := ""
find := false
for _, w := range LogList {
if ctx.Request.URL.Path == w.Api {
find = true
desc = w.Desc
}
}
if !find {
ctx.Next()
return
}
accId := ctx.GetInt64(AccId)
rawData, err := ctx.GetRawData()
ip := ipaddr.ResolveClientIP(ctx)
if err != nil {
ctx.AbortWithStatusJSON(400, err)
}
log.Info("OperateLog Test", log.Any("vmap.Path", ctx.Request.URL.Path))
err = oplog.AddLog(ctx, ctx.Request.URL.Path, desc, accId, string(rawData), ip)
if err != nil {
ctx.AbortWithStatusJSON(int(errors.OperateLog), err)
return
}
ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(rawData)) // 将取出来的执行条件放回ctx中
ctx.Next()
}
func GetAccount(ctx *gin.Context) int64 {
return ctx.GetInt64(AccId)
}