DengBiao před 9 měsíci
rodič
revize
e476ed246a
16 změnil soubory, kde provedl 466 přidání a 49 odebrání
  1. +12
    -0
      app/bigData/hdl/hdl_demo.go
  2. +59
    -0
      app/bigData/hdl/hdl_login.go
  3. +39
    -0
      app/bigData/lib/auth/auth.go
  4. +19
    -0
      app/bigData/lib/auth/base.go
  5. +33
    -0
      app/bigData/lib/validate/validate_comm.go
  6. +7
    -0
      app/bigData/md/md_app_redis_key.go
  7. +29
    -0
      app/bigData/md/md_login.go
  8. +30
    -0
      app/bigData/mw/mw_auth.go
  9. +29
    -0
      app/bigData/mw/mw_cors.go
  10. +58
    -0
      app/bigData/mw/mw_limiter.go
  11. +57
    -0
      app/bigData/mw/mw_recovery.go
  12. +44
    -0
      app/bigData/svc/svc_auth.go
  13. +32
    -0
      app/bigData/svc/svc_login.go
  14. +1
    -0
      app/router/admin_router.go
  15. +13
    -0
      app/router/big_data_router.go
  16. +4
    -49
      app/svc/svc_sys_cfg_get.go

+ 12
- 0
app/bigData/hdl/hdl_demo.go Zobrazit soubor

@@ -0,0 +1,12 @@
package hdl

import (
"applet/app/e"
"github.com/gin-gonic/gin"
)

// Demo 测试
func Demo(c *gin.Context) {
e.OutSuc(c, "success", nil)
return
}

+ 59
- 0
app/bigData/hdl/hdl_login.go Zobrazit soubor

@@ -0,0 +1,59 @@
package hdl

import (
"applet/app/bigData/lib/validate"
"applet/app/bigData/md"
"applet/app/bigData/svc"
"applet/app/e"
"applet/app/enum"
svc2 "applet/app/svc"
"applet/app/utils"
"fmt"
"github.com/gin-gonic/gin"
)

func Login(c *gin.Context) {
var req md.LoginReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
sysCfg := svc2.SysCfgFind(enum.BigDataScreenAccount, enum.BigDataScreenPassword)
if sysCfg[enum.BigDataScreenAccount] == "" || sysCfg[enum.BigDataScreenPassword] == "" {
e.OutErr(c, e.ERR_NO_DATA, "用户信息不存在")
return
}

if sysCfg[enum.BigDataScreenAccount] != req.Account || sysCfg[enum.BigDataScreenPassword] != req.Password {
e.OutErr(c, e.ERR_NO_DATA, "账号或密码错误")
return
}

ip := utils.GetIP(c.Request)
key := fmt.Sprintf(md.UserJwtTokenKey, ip)
token, err := svc.HandleLoginToken(key, &md.User{
Account: req.Account,
Password: req.Password,
})
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, md.LoginResponse{
Token: token,
}, nil)
return
}

func UserInfo(c *gin.Context) {
//1、获取用户信息
userInfo := svc.GetUser(c)

e.OutSuc(c, map[string]interface{}{
"user_info": userInfo,
}, nil)
return
}

+ 39
- 0
app/bigData/lib/auth/auth.go Zobrazit soubor

@@ -0,0 +1,39 @@
package auth

import (
"errors"
"github.com/dgrijalva/jwt-go"
"time"
)

// GenToken 生成JWT
func GenToken(account, password string) (string, error) {
// 创建一个我们自己的声明
c := JWTUser{
Account: account,
Password: password,
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
Issuer: "bakery", // 签发人
},
}
// 使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
// 使用指定的secret签名并获得完整的编码后的字符串token
return token.SignedString(Secret)
}

// ParseToken 解析JWT
func ParseToken(tokenString string) (*JWTUser, error) {
// 解析token
token, err := jwt.ParseWithClaims(tokenString, &JWTUser{}, func(token *jwt.Token) (i interface{}, err error) {
return Secret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*JWTUser); ok && token.Valid { // 校验token
return claims, nil
}
return nil, errors.New("invalid token")
}

+ 19
- 0
app/bigData/lib/auth/base.go Zobrazit soubor

@@ -0,0 +1,19 @@
package auth

import (
"time"

"github.com/dgrijalva/jwt-go"
)

// TokenExpireDuration is jwt 过期时间
const TokenExpireDuration = time.Hour * 4380

var Secret = []byte("bakery_big_data")

// JWTUser 如果想要保存更多信息,都可以添加到这个结构体中
type JWTUser struct {
Account string `json:"account"`
Password string `json:"password"`
jwt.StandardClaims
}

+ 33
- 0
app/bigData/lib/validate/validate_comm.go Zobrazit soubor

@@ -0,0 +1,33 @@
package validate

import (
"applet/app/e"
"applet/app/utils"
"applet/app/utils/logx"
"encoding/json"
"fmt"
"github.com/go-playground/validator/v10"
)

func HandleValidateErr(err error) error {
switch err.(type) {
case *json.UnmarshalTypeError:
return e.NewErr(e.ERR_UNMARSHAL, "参数格式错误")
case validator.ValidationErrors:
errs := err.(validator.ValidationErrors)
transMsgMap := errs.Translate(utils.ValidatorTrans) // utils.ValidatorTrans \app\utils\validator_err_trans.go::ValidatorTransInit初始化获得
transMsgOne := transMsgMap[GetOneKeyOfMapString(transMsgMap)]
return e.NewErr(e.ERR_INVALID_ARGS, transMsgOne)
default:
_ = logx.Error(err)
return e.NewErr(e.ERR, fmt.Sprintf("validate request params, err:%v\n", err))
}
}

// GetOneKeyOfMapString 取出Map的一个key
func GetOneKeyOfMapString(collection map[string]string) string {
for k := range collection {
return k
}
return ""
}

+ 7
- 0
app/bigData/md/md_app_redis_key.go Zobrazit soubor

@@ -0,0 +1,7 @@
package md

// 缓存key统一管理
const (
UserJwtTokenKey = "%s:bakery_big_data_user_jwt_token" // jwt, 占位符:ip, user:id
JwtTokenCacheTime = 3600 * 24 * 1
)

+ 29
- 0
app/bigData/md/md_login.go Zobrazit soubor

@@ -0,0 +1,29 @@
package md

type LoginReq struct {
Account string `json:"account" binding:"required" label:"账号"`
Password string `json:"password" binding:"required" label:"密码"`
}

type User struct {
Account string `json:"account" label:"账号"`
Password string `json:"password" label:"密码"`
}

type LoginResponse struct {
Token string `json:"token"`
}

type WxAppletLoginResponse struct {
OpenId string `json:"open_id"`
UnionId string `json:"union_id"`
}

type RegisterReq struct {
UserId string `json:"user_id" label:"支付宝用户的唯一userId"`
OpenId string `json:"open_id" label:"微信小程序openid"`
UnionId string `json:"union_id" label:"微信unionId"`
Nickname string `json:"nickname" label:"支付宝昵称"`
Avatar string `json:"avatar" label:"支付宝头像"`
Phone string `json:"phone" binding:"required" label:"手机号"`
}

+ 30
- 0
app/bigData/mw/mw_auth.go Zobrazit soubor

@@ -0,0 +1,30 @@
package mw

import (
"applet/app/bigData/svc"
"applet/app/e"
"github.com/gin-gonic/gin"
)

// 检查权限, 签名等等
func Auth(c *gin.Context) {
user, err := svc.CheckUser(c)
if err != nil {
switch err.(type) {
case e.E:
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
default:
e.OutErr(c, e.ERR_UNAUTHORIZED, err.Error())
return
}
}
if user == nil {
e.OutErr(c, e.ERR_NOT_AUTH, "当前用户信息失效")
return
}
// 将当前请求的username信息保存到请求的上下文c上
c.Set("user", user)
c.Next()
}

+ 29
- 0
app/bigData/mw/mw_cors.go Zobrazit soubor

@@ -0,0 +1,29 @@
package mw

import (
"github.com/gin-gonic/gin"
)

// cors跨域
func Cors(c *gin.Context) {
// 放行所有OPTIONS方法
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}

origin := c.Request.Header.Get("Origin") // 请求头部
if origin != "" {
c.Header("Access-Control-Allow-Origin", origin) // 这是允许访问来源域
c.Header("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE,UPDATE") // 服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
// header的类型
c.Header("Access-Control-Allow-Headers", "Authorization,Content-Length,X-CSRF-Token,Token,session,X_Requested_With,Accept,Origin,Host,Connection,Accept-Encoding,Accept-Language,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Pragma,X-Mx-ReqToken")
// 允许跨域设置,可以返回其他子段
// 跨域关键设置 让浏览器可以解析
c.Header("Access-Control-Expose-Headers", "Content-Length,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
c.Header("Access-Control-Max-Age", "172800") // 缓存请求信息 单位为秒
c.Header("Access-Control-Allow-Credentials", "false") // 跨域请求是否需要带cookie信息 默认设置为true
c.Set("Content-Type", "Application/json") // 设置返回格式是json
}
c.Next()
}

+ 58
- 0
app/bigData/mw/mw_limiter.go Zobrazit soubor

@@ -0,0 +1,58 @@
package mw

import (
"bytes"
"io/ioutil"

"github.com/gin-gonic/gin"

"applet/app/utils"
"applet/app/utils/cache"
)

// 限流器
func Limiter(c *gin.Context) {
limit := 100 // 限流次数
ttl := 1 // 限流过期时间
ip := c.ClientIP()
// 读取token或者ip
token := c.GetHeader("Authorization")
// 判断是否已经超出限额次数
method := c.Request.Method
host := c.Request.Host
uri := c.Request.URL.String()

buf := make([]byte, 2048)
num, _ := c.Request.Body.Read(buf)
body := buf[:num]
// Write body back
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
Md5 := utils.Md5(ip + token + method + host + uri + string(body))
if cache.Exists(Md5) {
c.AbortWithStatusJSON(429, gin.H{
"code": 429,
"msg": "don't repeat the request",
"data": struct{}{},
})
return
}
// 2s后没返回自动释放
go cache.SetEx(Md5, "0", ttl)
key := "LIMITER_" + ip
reqs, _ := cache.GetInt(key)
if reqs >= limit {
c.AbortWithStatusJSON(429, gin.H{
"code": 429,
"msg": "too many requests",
"data": struct{}{},
})
return
}
if reqs > 0 {
go cache.Incr(key)
} else {
go cache.SetEx(key, 1, ttl)
}
c.Next()
go cache.Del(Md5)
}

+ 57
- 0
app/bigData/mw/mw_recovery.go Zobrazit soubor

@@ -0,0 +1,57 @@
package mw

import (
"net"
"net/http"
"net/http/httputil"
"os"
"runtime/debug"
"strings"

"github.com/gin-gonic/gin"
"go.uber.org/zap"
)

func Recovery(logger *zap.Logger, stack bool) gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
var brokenPipe bool
if ne, ok := err.(*net.OpError); ok {
if se, ok := ne.Err.(*os.SyscallError); ok {
if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
brokenPipe = true
}
}
}

httpRequest, _ := httputil.DumpRequest(c.Request, false)
if brokenPipe {
logger.Error(c.Request.URL.Path,
zap.Any("error", err),
zap.String("request", string(httpRequest)),
)
// If the connection is dead, we can't write a status to it.
c.Error(err.(error))
c.Abort()
return
}

if stack {
logger.Error("[Recovery from panic]",
zap.Any("error", err),
zap.String("request", string(httpRequest)),
zap.String("stack", string(debug.Stack())),
)
} else {
logger.Error("[Recovery from panic]",
zap.Any("error", err),
zap.String("request", string(httpRequest)),
)
}
c.AbortWithStatus(http.StatusInternalServerError)
}
}()
c.Next()
}
}

+ 44
- 0
app/bigData/svc/svc_auth.go Zobrazit soubor

@@ -0,0 +1,44 @@
package svc

import (
"applet/app/bigData/lib/auth"
"applet/app/bigData/md"
"errors"
"github.com/gin-gonic/gin"
"strings"
)

func GetUser(c *gin.Context) *md.User {
user, _ := c.Get("user")
if user == nil {
return &md.User{
Account: "",
Password: "",
}
}
return user.(*md.User)
}

func CheckUser(c *gin.Context) (*md.User, error) {
token := c.GetHeader("Authorization")
if token == "" {
return nil, errors.New("token not exist")
}
// 按空格分割
parts := strings.SplitN(token, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
return nil, errors.New("token format error")
}
// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它
mc, err := auth.ParseToken(parts[1])
if err != nil {
return nil, err
}

// 获取user
user := &md.User{
Account: mc.Account,
Password: mc.Password,
}
return user, nil
}

+ 32
- 0
app/bigData/svc/svc_login.go Zobrazit soubor

@@ -0,0 +1,32 @@
package svc

import (
"applet/app/bigData/lib/auth"
"applet/app/bigData/md"
"applet/app/utils/cache"
"applet/app/utils/logx"
)

func HandleLoginToken(cacheKey string, user *md.User) (string, error) {
// 获取之前生成的token
token, err := cache.GetString(cacheKey)
if err != nil {
_ = logx.Error(err)
}
// 没有获取到
if err != nil || token == "" {
// 生成token
token, err = auth.GenToken(user.Account, user.Password)
if err != nil {
return "", err
}
// 缓存token
_, err = cache.SetEx(cacheKey, token, md.JwtTokenCacheTime)
if err != nil {
return "", err
}
return token, nil
}

return token, nil
}

+ 1
- 0
app/router/admin_router.go Zobrazit soubor

@@ -37,6 +37,7 @@ func Init() *gin.Engine {
r.Use(mw.Cors)
AdminRoute(r.Group("/api/admin"))
IpadInit(r.Group("/api/ipad"))
BigDataInit(r.Group("/api/bigData"))
return r
}



+ 13
- 0
app/router/big_data_router.go Zobrazit soubor

@@ -0,0 +1,13 @@
package router

import (
"applet/app/bigData/hdl"
"applet/app/ipad/mw"
"github.com/gin-gonic/gin"
)

func BigDataInit(r *gin.RouterGroup) {
r.POST("/test", hdl.Demo)
r.Use(mw.Auth) //检测登录状态

}

+ 4
- 49
app/svc/svc_sys_cfg_get.go Zobrazit soubor

@@ -26,33 +26,18 @@ func SysCfgDel(c *gin.Context, key string) bool {
}

// 多条记录获取
func SysCfgFind(c *gin.Context, keys ...string) map[string]string {
var masterId string
if c == nil {
masterId = ""
} else {
masterId = c.GetString("mid")
}
tmp := SysCfgFindComm(masterId, keys...)
func SysCfgFind(keys ...string) map[string]string {
tmp := SysCfgFindComm(keys...)
return tmp
}

// SysCfgGetByMasterId get one config by master id
func SysCfgGetByMasterId(masterId, key string) string {
res := SysCfgFindComm(masterId, key)
if _, ok := res[key]; !ok {
return ""
}
return res[key]
}

// SysCfgFindComm get cfg by master id
func SysCfgFindComm(masterId string, keys ...string) map[string]string {
func SysCfgFindComm(keys ...string) map[string]string {
sysCfgDb := db.SysCfgDb{}
sysCfgDb.Set()
res := map[string]string{}

cfgKey := fmt.Sprintf("%s:cfg_cache", masterId)
cfgKey := fmt.Sprintf("%s:cfg_cache")

err := cache.GetJson(cfgKey, &res)
if err != nil || len(res) == 0 {
@@ -79,36 +64,6 @@ func SysCfgFindComm(masterId string, keys ...string) map[string]string {
return tmp
}

// 多条记录获取
func EgSysCfgFind(keys ...string) map[string]string {
sysCfgDb := db.SysCfgDb{}
sysCfgDb.Set()
res := map[string]string{}
if len(res) == 0 {
cfgList, _ := sysCfgDb.SysCfgGetAll()
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
// 先不设置缓存
// cache.SetJson(md.KEY_SYS_CFG_CACHE, res, 60)
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// 清理系统配置信息
func SysCfgCleanCache(c *gin.Context) {
var tmp = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}


Načítá se…
Zrušit
Uložit