2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 07:57:21 +08:00

refactor: 使用session鉴权

This commit is contained in:
耗子
2024-07-11 02:51:49 +08:00
parent 7907345521
commit c4e01b37b7
11 changed files with 171 additions and 117 deletions

View File

@@ -2,7 +2,6 @@ package controllers
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"github.com/swaggo/http-swagger/v2"
_ "github.com/TheTNB/panel/docs"
@@ -25,10 +24,6 @@ func NewSwaggerController() *SwaggerController {
// @Failure 500
// @Router /swagger [get]
func (r *SwaggerController) Index(ctx http.Context) http.Response {
if !facades.Config().GetBool("app.debug") {
return Error(ctx, http.StatusNotFound, http.StatusText(http.StatusNotFound))
}
handler := httpSwagger.Handler()
handler(ctx.Response().Writer(), ctx.Request().Origin())

View File

@@ -1,8 +1,11 @@
package controllers
import (
"fmt"
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"github.com/spf13/cast"
"github.com/TheTNB/panel/app/http/requests/user"
"github.com/TheTNB/panel/app/models"
@@ -20,16 +23,15 @@ func NewUserController() *UserController {
// Login
//
// @Summary 登录
// @Description 通过用户名和密码获取访问令牌
// @Tags 用户鉴权
// @Accept json
// @Produce json
// @Param data body requests.Login true "request"
// @Success 200 {object} SuccessResponse
// @Failure 403 {object} ErrorResponse "用户名或密码错误"
// @Failure 500 {object} ErrorResponse "系统内部错误
// @Router /panel/user/login [post]
// @Summary 登录
// @Tags 用户鉴权
// @Accept json
// @Produce json
// @Param data body requests.Login true "request"
// @Success 200 {object} SuccessResponse
// @Failure 403 {object} ErrorResponse "用户名或密码错误"
// @Failure 500 {object} ErrorResponse "系统内部错误
// @Router /panel/user/login [post]
func (r *UserController) Login(ctx http.Context) http.Response {
var loginRequest requests.Login
sanitize := SanitizeRequest(ctx, &loginRequest)
@@ -60,32 +62,38 @@ func (r *UserController) Login(ctx http.Context) http.Response {
}
}
token, loginErr := facades.Auth(ctx).LoginUsingID(user.ID)
if loginErr != nil {
facades.Log().Request(ctx.Request()).Tags("面板", "用户").With(map[string]any{
"error": err.Error(),
}).Info("登录失败")
return ErrorSystem(ctx)
ctx.Request().Session().Put("user_id", user.ID)
return Success(ctx, nil)
}
// Logout
//
// @Summary 登出
// @Tags 用户鉴权
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
// @Router /panel/user/logout [post]
func (r *UserController) Logout(ctx http.Context) http.Response {
if err := ctx.Request().Session().Invalidate(); err != nil {
return Error(ctx, http.StatusInternalServerError, fmt.Sprintf("登出失败: %s", err.Error()))
}
return Success(ctx, http.Json{
"access_token": token,
})
return Success(ctx, nil)
}
// Info
//
// @Summary 用户信息
// @Description 获取当前登录用户信息
// @Tags 用户鉴权
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
// @Router /panel/user/info [get]
// @Summary 用户信息
// @Tags 用户鉴权
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
// @Router /panel/user/info [get]
func (r *UserController) Info(ctx http.Context) http.Response {
userID := cast.ToUint(ctx.Value("user_id"))
var user models.User
err := facades.Auth(ctx).User(&user)
if err != nil {
if err := facades.Orm().Query().Where("id", userID).Get(&user); err != nil {
facades.Log().Request(ctx.Request()).Tags("面板", "用户").With(map[string]any{
"error": err.Error(),
}).Info("获取用户信息失败")

View File

@@ -1,47 +0,0 @@
package middleware
import (
"errors"
"github.com/goravel/framework/auth"
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
)
// Jwt 确保通过 JWT 鉴权
func Jwt() http.Middleware {
return func(ctx http.Context) {
translate := facades.Lang(ctx)
token := ctx.Request().Header("Authorization", ctx.Request().Header("Sec-WebSocket-Protocol"))
if len(token) == 0 {
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
"message": translate.Get("auth.token.missing"),
})
return
}
// JWT 鉴权
if _, err := facades.Auth(ctx).Parse(token); err != nil {
if errors.Is(err, auth.ErrorTokenExpired) {
token, err = facades.Auth(ctx).Refresh()
if err != nil {
// 到达刷新时间上限
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
"message": translate.Get("auth.token.expired"),
})
return
}
token = "Bearer " + token
} else {
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
"message": translate.Get("auth.token.expired"),
})
return
}
}
ctx.Response().Header("Authorization", token)
ctx.Request().Next()
}
}

View File

@@ -0,0 +1,39 @@
package middleware
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"github.com/spf13/cast"
)
// Session 确保通过 JWT 鉴权
func Session() http.Middleware {
return func(ctx http.Context) {
translate := facades.Lang(ctx)
if !ctx.Request().HasSession() {
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
"message": translate.Get("auth.session.missing"),
})
return
}
if ctx.Request().Session().Missing("user_id") {
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
"message": translate.Get("auth.session.expired"),
})
return
}
userID := cast.ToUint(ctx.Request().Session().Get("user_id"))
if userID == 0 {
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
"message": translate.Get("auth.session.invalid"),
})
return
}
ctx.WithValue("user_id", userID)
ctx.Request().Next()
}
}

View File

@@ -3235,7 +3235,6 @@ const docTemplate = `{
"BearerToken": []
}
],
"description": "获取当前登录用户信息",
"produces": [
"application/json"
],
@@ -3255,7 +3254,6 @@ const docTemplate = `{
},
"/panel/user/login": {
"post": {
"description": "通过用户名和密码获取访问令牌",
"consumes": [
"application/json"
],
@@ -3299,6 +3297,30 @@ const docTemplate = `{
}
}
},
"/panel/user/logout": {
"post": {
"security": [
{
"BearerToken": []
}
],
"produces": [
"application/json"
],
"tags": [
"用户鉴权"
],
"summary": "登出",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/controllers.SuccessResponse"
}
}
}
}
},
"/panel/website/backupList": {
"get": {
"security": [

View File

@@ -3228,7 +3228,6 @@
"BearerToken": []
}
],
"description": "获取当前登录用户信息",
"produces": [
"application/json"
],
@@ -3248,7 +3247,6 @@
},
"/panel/user/login": {
"post": {
"description": "通过用户名和密码获取访问令牌",
"consumes": [
"application/json"
],
@@ -3292,6 +3290,30 @@
}
}
},
"/panel/user/logout": {
"post": {
"security": [
{
"BearerToken": []
}
],
"produces": [
"application/json"
],
"tags": [
"用户鉴权"
],
"summary": "登出",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/controllers.SuccessResponse"
}
}
}
}
},
"/panel/website/backupList": {
"get": {
"security": [

View File

@@ -2645,7 +2645,6 @@ paths:
- 系统
/panel/user/info:
get:
description: 获取当前登录用户信息
produces:
- application/json
responses:
@@ -2662,7 +2661,6 @@ paths:
post:
consumes:
- application/json
description: 通过用户名和密码获取访问令牌
parameters:
- description: request
in: body
@@ -2688,6 +2686,20 @@ paths:
summary: 登录
tags:
- 用户鉴权
/panel/user/logout:
post:
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 登出
tags:
- 用户鉴权
/panel/website/backupList:
get:
parameters:

View File

@@ -1,8 +1,9 @@
{
"auth": {
"token": {
"expired": "login has expired",
"missing": "not logged in"
"session": {
"expired": "session has expired",
"missing": "Please enable cookies and try again",
"invalid": "invalid session"
}
},
"commands": {

View File

@@ -1,8 +1,9 @@
{
"auth": {
"token": {
"expired": "登录已过期",
"missing": "未登录"
"session": {
"expired": "会话已过期",
"missing": "请启用 Cookie 后再试",
"invalid": "会话无效"
}
},
"commands": {

View File

@@ -14,29 +14,30 @@ func Api() {
r.Prefix("info").Group(func(r route.Router) {
infoController := controllers.NewInfoController()
r.Get("panel", infoController.Panel)
r.Middleware(middleware.Jwt()).Get("homePlugins", infoController.HomePlugins)
r.Middleware(middleware.Jwt()).Get("nowMonitor", infoController.NowMonitor)
r.Middleware(middleware.Jwt()).Get("systemInfo", infoController.SystemInfo)
r.Middleware(middleware.Jwt()).Get("countInfo", infoController.CountInfo)
r.Middleware(middleware.Jwt()).Get("installedDbAndPhp", infoController.InstalledDbAndPhp)
r.Middleware(middleware.Jwt()).Get("checkUpdate", infoController.CheckUpdate)
r.Middleware(middleware.Jwt()).Get("updateInfo", infoController.UpdateInfo)
r.Middleware(middleware.Jwt()).Post("update", infoController.Update)
r.Middleware(middleware.Jwt()).Post("restart", infoController.Restart)
r.Middleware(middleware.Session()).Get("homePlugins", infoController.HomePlugins)
r.Middleware(middleware.Session()).Get("nowMonitor", infoController.NowMonitor)
r.Middleware(middleware.Session()).Get("systemInfo", infoController.SystemInfo)
r.Middleware(middleware.Session()).Get("countInfo", infoController.CountInfo)
r.Middleware(middleware.Session()).Get("installedDbAndPhp", infoController.InstalledDbAndPhp)
r.Middleware(middleware.Session()).Get("checkUpdate", infoController.CheckUpdate)
r.Middleware(middleware.Session()).Get("updateInfo", infoController.UpdateInfo)
r.Middleware(middleware.Session()).Post("update", infoController.Update)
r.Middleware(middleware.Session()).Post("restart", infoController.Restart)
})
r.Prefix("user").Group(func(r route.Router) {
userController := controllers.NewUserController()
r.Middleware(frameworkmiddleware.Throttle("login")).Post("login", userController.Login)
r.Middleware(middleware.Jwt()).Get("info", userController.Info)
r.Post("logout", userController.Logout)
r.Middleware(middleware.Session()).Get("info", userController.Info)
})
r.Prefix("task").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("task").Middleware(middleware.Session()).Group(func(r route.Router) {
taskController := controllers.NewTaskController()
r.Get("status", taskController.Status)
r.Get("list", taskController.List)
r.Get("log", taskController.Log)
r.Post("delete", taskController.Delete)
})
r.Prefix("website").Middleware(middleware.Jwt(), middleware.MustInstall()).Group(func(r route.Router) {
r.Prefix("website").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
websiteController := controllers.NewWebsiteController()
r.Get("defaultConfig", websiteController.GetDefaultConfig)
r.Post("defaultConfig", websiteController.SaveDefaultConfig)
@@ -44,7 +45,7 @@ func Api() {
r.Put("uploadBackup", websiteController.UploadBackup)
r.Delete("deleteBackup", websiteController.DeleteBackup)
})
r.Prefix("websites").Middleware(middleware.Jwt(), middleware.MustInstall()).Group(func(r route.Router) {
r.Prefix("websites").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
websiteController := controllers.NewWebsiteController()
r.Get("/", websiteController.List)
r.Post("/", websiteController.Add)
@@ -58,7 +59,7 @@ func Api() {
r.Post("{id}/resetConfig", websiteController.ResetConfig)
r.Post("{id}/status", websiteController.Status)
})
r.Prefix("cert").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("cert").Middleware(middleware.Session()).Group(func(r route.Router) {
certController := controllers.NewCertController()
r.Get("caProviders", certController.CAProviders)
r.Get("dnsProviders", certController.DNSProviders)
@@ -83,7 +84,7 @@ func Api() {
r.Post("manualDNS", certController.ManualDNS)
r.Post("deploy", certController.Deploy)
})
r.Prefix("plugin").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("plugin").Middleware(middleware.Session()).Group(func(r route.Router) {
pluginController := controllers.NewPluginController()
r.Get("list", pluginController.List)
r.Post("install", pluginController.Install)
@@ -92,7 +93,7 @@ func Api() {
r.Post("updateShow", pluginController.UpdateShow)
r.Get("isInstalled", pluginController.IsInstalled)
})
r.Prefix("cron").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("cron").Middleware(middleware.Session()).Group(func(r route.Router) {
cronController := controllers.NewCronController()
r.Get("list", cronController.List)
r.Get("{id}", cronController.Script)
@@ -102,7 +103,7 @@ func Api() {
r.Post("status", cronController.Status)
r.Get("log/{id}", cronController.Log)
})
r.Prefix("safe").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("safe").Middleware(middleware.Session()).Group(func(r route.Router) {
safeController := controllers.NewSafeController()
r.Get("firewallStatus", safeController.GetFirewallStatus)
r.Post("firewallStatus", safeController.SetFirewallStatus)
@@ -116,7 +117,7 @@ func Api() {
r.Get("pingStatus", safeController.GetPingStatus)
r.Post("pingStatus", safeController.SetPingStatus)
})
r.Prefix("container").Middleware(middleware.Jwt(), middleware.MustInstall()).Group(func(r route.Router) {
r.Prefix("container").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
containerController := controllers.NewContainerController()
r.Get("list", containerController.ContainerList)
r.Get("search", containerController.ContainerSearch)
@@ -164,7 +165,7 @@ func Api() {
r.Post("prune", containerController.VolumePrune)
})
})
r.Prefix("file").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("file").Middleware(middleware.Session()).Group(func(r route.Router) {
fileController := controllers.NewFileController()
r.Post("create", fileController.Create)
r.Get("content", fileController.Content)
@@ -182,7 +183,7 @@ func Api() {
r.Post("search", fileController.Search)
r.Get("list", fileController.List)
})
r.Prefix("monitor").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("monitor").Middleware(middleware.Session()).Group(func(r route.Router) {
monitorController := controllers.NewMonitorController()
r.Post("switch", monitorController.Switch)
r.Post("saveDays", monitorController.SaveDays)
@@ -190,20 +191,20 @@ func Api() {
r.Get("list", monitorController.List)
r.Get("switchAndDays", monitorController.SwitchAndDays)
})
r.Prefix("ssh").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("ssh").Middleware(middleware.Session()).Group(func(r route.Router) {
sshController := controllers.NewSshController()
r.Get("info", sshController.GetInfo)
r.Post("info", sshController.UpdateInfo)
r.Get("session", sshController.Session)
})
r.Prefix("setting").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("setting").Middleware(middleware.Session()).Group(func(r route.Router) {
settingController := controllers.NewSettingController()
r.Get("list", settingController.List)
r.Post("update", settingController.Update)
r.Get("https", settingController.GetHttps)
r.Post("https", settingController.UpdateHttps)
})
r.Prefix("system").Middleware(middleware.Jwt()).Group(func(r route.Router) {
r.Prefix("system").Middleware(middleware.Session()).Group(func(r route.Router) {
controller := controllers.NewSystemController()
r.Get("service/status", controller.ServiceStatus)
r.Get("service/isEnabled", controller.ServiceIsEnabled)
@@ -218,7 +219,7 @@ func Api() {
// 文档
swaggerController := controllers.NewSwaggerController()
facades.Route().Get("swagger/*any", swaggerController.Index)
facades.Route().Middleware(middleware.Session()).Get("swagger/*any", swaggerController.Index)
// 静态文件
entrance := facades.Config().GetString("http.entrance")

View File

@@ -10,7 +10,7 @@ import (
// Plugin 加载插件路由
func Plugin() {
facades.Route().Prefix("api/plugins").Middleware(middleware.Jwt(), middleware.MustInstall()).Group(func(r route.Router) {
facades.Route().Prefix("api/plugins").Middleware(middleware.Session(), middleware.MustInstall()).Group(func(r route.Router) {
r.Prefix("openresty").Group(func(route route.Router) {
openRestyController := plugins.NewOpenrestyController()
route.Get("load", openRestyController.Load)