Files

188 lines
4.8 KiB
Go

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
}