improve
     - AuthMiddleware 注入当前用户的信息
     - 增加Context服务支持快捷获取当前登录者信息
     - 重构Login/GetMe接口逻辑避免重复的数据库查询
     - 规范化error信息声明(向下兼容,旧代码可逐渐迁移规范化)
     - 修正部分不符合规范的代码
This commit is contained in:
yaziming
2019-08-31 21:22:47 +08:00
parent 55c6c6fd77
commit 81f6cf021f
9 changed files with 168 additions and 34 deletions

View File

@@ -0,0 +1,5 @@
package constants
const (
ContextUser = "currentUser"
)

View File

@@ -0,0 +1,8 @@
package constants
import "crawlab/errors"
var (
//users
ErrorUserNotFound = errors.NewBusinessError(10001, "user not found.")
)

43
backend/errors/errors.go Normal file
View File

@@ -0,0 +1,43 @@
package errors
import "fmt"
type Scope int
const (
ScopeSystem Scope = 1
ScopeBusiness Scope = 2
)
type OPError struct {
Message string
Code int
Scope Scope
}
func (O OPError) Error() string {
var scope string
switch O.Scope {
case ScopeSystem:
scope = "system"
break
case ScopeBusiness:
scope = "business"
}
return fmt.Sprintf("%s : %d -> %s.", scope, O.Code, O.Message)
}
func NewSystemOPError(code int, message string) *OPError {
return &OPError{
Message: message,
Code: code,
Scope: ScopeSystem,
}
}
func NewBusinessError(code int, message string) *OPError {
return &OPError{
Message: message,
Code: code,
Scope: ScopeBusiness,
}
}

View File

@@ -46,6 +46,7 @@ func AuthorizationMiddleware() gin.HandlerFunc {
return
}
}
c.Set(constants.ContextUser, &user)
// 校验成功
c.Next()

View File

@@ -113,7 +113,7 @@ func PutSchedule(c *gin.Context) {
func DeleteSchedule(c *gin.Context) {
id := bson.ObjectIdHex("5d429e6c19f7abede924fee2")
for _, sch := range scheduleList {
if sch.Id == bson.ObjectId(id) {
if sch.Id == id {
fmt.Println("delete a schedule")
}
}

View File

@@ -4,6 +4,7 @@ import (
"crawlab/constants"
"crawlab/model"
"crawlab/services"
"crawlab/services/context"
"crawlab/utils"
"github.com/gin-gonic/gin"
"github.com/globalsign/mgo/bson"
@@ -171,7 +172,7 @@ func Login(c *gin.Context) {
}
// 获取token
tokenStr, err := services.GetToken(user.Username)
tokenStr, err := services.MakeToken(&user)
if err != nil {
HandleError(http.StatusUnauthorized, c, errors.New("not authorized"))
return
@@ -185,20 +186,16 @@ func Login(c *gin.Context) {
}
func GetMe(c *gin.Context) {
// 获取token string
tokenStr := c.GetHeader("Authorization")
// 校验token
user, err := services.CheckToken(tokenStr)
if err != nil {
HandleError(http.StatusUnauthorized, c, errors.New("not authorized"))
ctx := context.WithGinContext(c)
user := ctx.User()
if user == nil {
ctx.FailedWithError(constants.ErrorUserNotFound, http.StatusUnauthorized)
return
}
user.Password = ""
c.JSON(http.StatusOK, Response{
Status: "ok",
Message: "success",
Data: user,
})
ctx.Success(struct {
*model.User
Password string `json:"password,omitempty"`
}{
User: user,
}, nil)
}

View File

@@ -0,0 +1,73 @@
package context
import (
"crawlab/constants"
"crawlab/errors"
"crawlab/model"
"fmt"
"github.com/apex/log"
"github.com/gin-gonic/gin"
errors2 "github.com/pkg/errors"
"net/http"
"runtime/debug"
)
type Context struct {
*gin.Context
}
func (c *Context) User() *model.User {
userIfe, exists := c.Get(constants.ContextUser)
if !exists {
return nil
}
user, ok := userIfe.(*model.User)
if !ok {
return nil
}
return user
}
func (c *Context) Success(data interface{}, meta interface{}) {
if meta == nil {
meta = gin.H{}
}
if data == nil {
data = gin.H{}
}
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"message": "success",
"data": data,
"error": "",
})
}
func (c *Context) FailedWithError(err error, httpCode ...int) {
var code = 200
if len(httpCode) > 0 {
code = httpCode[0]
}
log.Errorf("handle error:" + err.Error())
debug.PrintStack()
switch errors2.Cause(err).(type) {
case errors.OPError:
c.AbortWithStatusJSON(code, gin.H{
"status": "ok",
"message": "error",
"error": err.Error(),
})
break
default:
fmt.Println("deprecated....")
c.AbortWithStatusJSON(code, gin.H{
"status": "ok",
"message": "error",
"error": err.Error(),
})
}
}
func WithGinContext(context *gin.Context) *Context {
return &Context{Context: context}
}

View File

@@ -230,7 +230,7 @@ func ReadFileByStep(filePath string, handle func([]byte, *mgo.GridFile), fileCre
for {
switch nr, err := f.Read(s[:]); true {
case nr < 0:
fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
_, _ = fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
debug.PrintStack()
case nr == 0: // EOF
return nil
@@ -238,7 +238,6 @@ func ReadFileByStep(filePath string, handle func([]byte, *mgo.GridFile), fileCre
handle(s[0:nr], fileCreate)
}
}
return nil
}
// 发布所有爬虫

View File

@@ -5,11 +5,9 @@ import (
"crawlab/model"
"crawlab/utils"
"errors"
"github.com/apex/log"
"github.com/dgrijalva/jwt-go"
"github.com/globalsign/mgo/bson"
"github.com/spf13/viper"
"runtime/debug"
"time"
)
@@ -24,28 +22,38 @@ func InitUserService() error {
}
return nil
}
func GetToken(username string) (tokenStr string, err error) {
user, err := model.GetUserByUsername(username)
if err != nil {
log.Errorf(err.Error())
debug.PrintStack()
return
}
func MakeToken(user *model.User) (tokenStr string, err error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"id": user.Id,
"username": user.Username,
"nbf": time.Now().Unix(),
})
tokenStr, err = token.SignedString([]byte(viper.GetString("server.secret")))
if err != nil {
return
}
return
return token.SignedString([]byte(viper.GetString("server.secret")))
}
//func GetToken(username string) (tokenStr string, err error) {
// user, err := model.GetUserByUsername(username)
// if err != nil {
// log.Errorf(err.Error())
// debug.PrintStack()
// return
// }
//
// token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
// "id": user.Id,
// "username": user.Username,
// "nbf": time.Now().Unix(),
// })
//
// tokenStr, err = token.SignedString([]byte(viper.GetString("server.secret")))
// if err != nil {
// return
// }
// return
//}
func SecretFunc() jwt.Keyfunc {
return func(token *jwt.Token) (interface{}, error) {
return []byte(viper.GetString("server.secret")), nil