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/paycenter", } ) // 读取角色信息 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) }