package web import ( "fmt" "github.com/appleboy/gin-jwt/v2" "github.com/gin-gonic/gin" "time" "trojan/core" "trojan/util" "trojan/web/controller" ) var ( identityKey = "id" authMiddleware *jwt.GinJWTMiddleware err error ) // Login auth用户验证结构体 type Login struct { Username string `form:"username" json:"username" binding:"required"` Password string `form:"password" json:"password" binding:"required"` } func getSecretKey() string { sk, _ := core.GetValue("secretKey") if sk == "" { sk = util.RandString(15, util.ALL) core.SetValue("secretKey", sk) } return sk } func jwtInit(timeout int) { authMiddleware, err = jwt.New(&jwt.GinJWTMiddleware{ Realm: "trojan-manager", Key: []byte(getSecretKey()), Timeout: time.Minute * time.Duration(timeout), MaxRefresh: time.Minute * time.Duration(timeout), IdentityKey: identityKey, SendCookie: true, PayloadFunc: func(data interface{}) jwt.MapClaims { if v, ok := data.(*Login); ok { return jwt.MapClaims{ identityKey: v.Username, } } return jwt.MapClaims{} }, IdentityHandler: func(c *gin.Context) interface{} { claims := jwt.ExtractClaims(c) return &Login{ Username: claims[identityKey].(string), } }, Authenticator: func(c *gin.Context) (interface{}, error) { var ( password string loginVals Login ) if err := c.ShouldBind(&loginVals); err != nil { return "", jwt.ErrMissingLoginValues } userID := loginVals.Username pass := loginVals.Password if err != nil { return nil, err } if userID != "admin" { mysql := core.GetMysql() user := mysql.GetUserByName(userID) if user == nil { return nil, jwt.ErrFailedAuthentication } password = user.EncryptPass } else { if password, err = core.GetValue(userID + "_pass"); err != nil { return nil, err } } if password == pass { return &loginVals, nil } return nil, jwt.ErrFailedAuthentication }, Authorizator: func(data interface{}, c *gin.Context) bool { if _, ok := data.(*Login); ok { return true } return false }, Unauthorized: func(c *gin.Context, code int, message string) { c.JSON(code, gin.H{ "code": code, "message": message, }) }, TokenLookup: "header: Authorization, query: token, cookie: jwt", TokenHeadName: "Bearer", TimeFunc: time.Now, }) if err != nil { fmt.Println("JWT Error:" + err.Error()) } } func updateUser(c *gin.Context) { responseBody := controller.ResponseBody{Msg: "success"} defer controller.TimeCost(time.Now(), &responseBody) username := c.DefaultPostForm("username", "admin") pass := c.PostForm("password") err := core.SetValue(fmt.Sprintf("%s_pass", username), pass) if err != nil { responseBody.Msg = err.Error() } c.JSON(200, responseBody) } // RequestUsername 获取请求接口的用户名 func RequestUsername(c *gin.Context) string { claims := jwt.ExtractClaims(c) return claims[identityKey].(string) } func RequireAdmin(c *gin.Context) bool { if RequestUsername(c) == "admin" { return true } c.JSON(403, gin.H{"code": 403, "message": "administrator access required"}) return false } // Auth 权限router func Auth(r *gin.Engine, timeout int) *jwt.GinJWTMiddleware { jwtInit(timeout) newInstall := gin.H{"code": 201, "message": "No administrator account found inside the database", "data": nil} r.NoRoute(authMiddleware.MiddlewareFunc(), func(c *gin.Context) { claims := jwt.ExtractClaims(c) fmt.Printf("NoRoute claims: %#v\n", claims) c.JSON(404, gin.H{"code": 404, "message": "Page not found"}) }) r.GET("/auth/check", func(c *gin.Context) { result, _ := core.GetValue("admin_pass") if result == "" { c.JSON(201, newInstall) } else { title, err := core.GetValue("login_title") if err != nil { title = "trojan 管理平台" } c.JSON(200, gin.H{ "code": 200, "message": "success", "data": map[string]string{ "title": title, }, }) } }) r.POST("/auth/login", authMiddleware.LoginHandler) r.POST("/auth/register", func(c *gin.Context) { if result, _ := core.GetValue("admin_pass"); result != "" { c.JSON(403, gin.H{"code":403,"message":"administrator already initialized"}); return } updateUser(c) }) authO := r.Group("/auth") authO.Use(authMiddleware.MiddlewareFunc()) { authO.GET("/loginUser", func(c *gin.Context) { result, _ := core.GetValue("admin_pass") if result == "" { c.JSON(201, newInstall) } else { c.JSON(200, gin.H{ "code": 200, "message": "success", "data": map[string]string{ "username": RequestUsername(c), }, }) } }) authO.POST("/reset_pass", updateUser) authO.POST("/logout", authMiddleware.LogoutHandler) authO.POST("/refresh_token", authMiddleware.RefreshHandler) } return authMiddleware }