package middleware import ( "encoding/json" "eta/eta_mini_ht_api/common/component/cache" logger "eta/eta_mini_ht_api/common/component/log" "eta/eta_mini_ht_api/common/exception" authUtils "eta/eta_mini_ht_api/common/utils/auth" "eta/eta_mini_ht_api/common/utils/jwt" "eta/eta_mini_ht_api/common/utils/redis" stringUtils "eta/eta_mini_ht_api/common/utils/string" "eta/eta_mini_ht_api/controllers" "eta/eta_mini_ht_api/service/user" "github.com/beego/beego/v2/server/web" "github.com/beego/beego/v2/server/web/context" "github.com/google/uuid" "strings" ) var ( rdCache *cache.RedisCache ) const ( ILLEGALUSER = "用户信息异常" UNAUTHORIZED = "请重新登录" TOKENEXPIRED = "token过期" LOGINREQURED = "重新登录" FORBIDDEN = "禁止访问" NOTFOUND = "未找到" authorization = "Authorization" baseUrl = "/htapi" Bearer = "Bearer" ) func rd() *cache.RedisCache { if rdCache == nil { rdCache = cache.GetInstance() } return rdCache } var detailRoutes = []string{ "/media/media", "/report/report", "/media/list", "/report/list", "/media/search", "/report/search", "/report/hotRankedList", "/report/publishRankedList", "/home/search", } var publicRoutes = []string{ "/auth/areaCodes", "/auth/wxAppid", "/auth/notice", "/auth/disclaimer", "/auth/refreshToken", "/auth/sendCode", "/user/bind_gzh", "/user/wx/notify", "/webhook/*", "/chart/updateChartImage", } var privateRoutes = []string{ "/user/profile", "/user/followAnalyst", "/user/followAnalysts", "/user/followingAnalystList", "/user/readMessages", "/user/readMessage", "/user/bookMark", "/user/unBookMark", "/user/checkBookMark", "/user/bookMarkList", "/user/bookMarkSearch", "/user/feedback", "/webhook/*", "/user/checkFollowStatus", "/user/followingAnalysts", "/user/message", "/analyst/analystDetail", "/analyst/list", "/analyst/reportList", "/analyst/mediaList", "/media/count", "/report/count", "/product/*", "/order/*", "/user/order/*", } func encoding(data interface{}) []byte { content, err := json.Marshal(data) if err != nil { logger.Error("json 序列化失败", err) return []byte{} } if !htConfig.NeedEncode() { return content } content = authUtils.DesBase64Encrypt(content, htConfig.GetDesCode()) content = []byte(`"` + string(content) + `"`) logger.Info("返回报文%s", string(content)) return content } func AuthMiddleware() web.FilterFunc { return func(ctx *context.Context) { threadId := strings.ReplaceAll(uuid.New().String(), "-", "") ctx.Input.SetData("threadId", threadId) path := ctx.Input.URL() logger.Info("请求路径:%v", path) if !allowed(path) { rep := unAuthorized() auth := ctx.Input.Header(authorization) if auth == "" { logger.Error("token信息不存在") _ = ctx.Output.Body(encoding(rep)) return } parts := strings.Split(auth, " ") if len(parts) != 2 || parts[0] != Bearer { logger.Error("token参数不符合格式" + auth) _ = ctx.Output.Body(encoding(rep)) return } info, err := jwt.CheckToken(parts[1]) if err != nil { logger.Error("token无效:%v", err) _ = ctx.Output.Body(encoding(rep)) return } //组装用户信息 var userInfo user.User userInfo, err = user.GetUserByOpenId(info.OpenId) if err != nil { logger.Error("获取用户信息失败:%v", err) _ = ctx.Output.Body(encoding(illegalUser())) return } //校验redis中是否合法 redisToken := rd().GetString(redis.GenerateTokenKey(info.OpenId)) if redisToken == "" { logger.Error("token无效:token已失效") //重置用户状态为登出 //err = userService.UserLogout(userInfo.Id) //if err != nil { // logger.Error("重置用户状态失败:%v", err) //} _ = ctx.Output.Body(encoding(tokenExpired())) return } if redisToken != parts[1] { logger.Error("token无效:用户token已刷新") _ = ctx.Output.Body(encoding(tokenExpired())) return } if needCheckLoginStatus(path) { if info.TokenType != jwt.AccessToken || info.Mobile == "-" || info.Mobile == "" { logger.Error("token信息异常,当前token类型为:%v", jwt.GuestToken) _ = ctx.Output.Body(encoding(LoginRequired())) return } } //详情信息需要登录token才能看到全部 if loginForDetail(path) { if info.TokenType != jwt.AccessToken || info.Mobile == "-" || info.Mobile == "" { ctx.Input.SetData("detailType", "logout") } else { ctx.Input.SetData("detailType", "login") } } //if userInfo.Mobile == "-" && path != baseUrl+"/auth/login" { // logger.Error("用户手机号为空:%v", err) // _ = ctx.JSONResp(illegalUser()) // return //} ctx.Input.SetData("user", userInfo) return } return } } func unAuthorized() controllers.BaseResponse { return controllers.BaseResponse{ Ret: 401, Msg: UNAUTHORIZED, ErrMsg: exception.GetMsg(exception.Unauthorized), } } func webhookSysErr(message string) controllers.BaseResponse { return controllers.BaseResponse{ Ret: 401, Msg: message, ErrMsg: exception.GetMsg(exception.SysError), } } func webhookUnauthorized(message string) controllers.BaseResponse { return controllers.BaseResponse{ Ret: 401, Msg: message, ErrMsg: exception.GetMsg(exception.Unauthorized), } } func tokenExpired() controllers.BaseResponse { return controllers.BaseResponse{ Ret: 401, Msg: TOKENEXPIRED, ErrMsg: exception.GetMsg(exception.Unauthorized), } } func LoginRequired() controllers.BaseResponse { return controllers.BaseResponse{ Ret: 408, Msg: LOGINREQURED, ErrMsg: exception.GetMsg(exception.Unauthorized), } } func illegalUser() controllers.BaseResponse { return controllers.BaseResponse{ Ret: 401, Msg: ILLEGALUSER, ErrMsg: exception.GetMsg(exception.Unauthorized), } } func allowed(path string) bool { for _, p := range publicRoutes { if stringUtils.IsBlank(p) { continue } src := baseUrl + p if strings.HasSuffix(p, "*") { target := src[:len(src)-1] if strings.HasPrefix(path, target) { return true } } else { if src == path { return true } } } return false } func loginForDetail(path string) bool { for _, p := range detailRoutes { if stringUtils.IsBlank(p) { continue } src := baseUrl + p if strings.HasSuffix(p, "*") { target := src[:len(src)-1] if strings.HasPrefix(path, target) { return true } } else { if src == path { return true } } } return false } func needCheckLoginStatus(path string) bool { for _, p := range privateRoutes { if stringUtils.IsBlank(p) { continue } src := baseUrl + p if strings.HasSuffix(p, "*") { target := src[:len(src)-1] if strings.HasPrefix(path, target) { return true } } else { if src == path { return true } } } return false }