- 工具栏:面包屑与右侧组件像素级等高(:deep 34px)、合并重复search handler、统一分隔符样式、删除死代码 - 面板对齐:三面板header统一padding/font-size、文件列表分页固定底部(自定义紧凑)、表头默认隐藏、滚动条统一样式 - 预览区:始终显示空白预览面板、重启自动恢复上次打开文件 - 收藏夹:简化计数显示(共N项) - 远程连接:ConnectionIndicator自适应UI(无远程显示mini云图标)、ConnectionDialog支持编辑配置、transport抽象层(本地Wails/远程HTTP双模式)、agent后端模块
62 lines
1.6 KiB
Go
62 lines
1.6 KiB
Go
package middleware
|
||
|
||
import (
|
||
"crypto/subtle"
|
||
"net/http"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/labstack/echo/v4"
|
||
)
|
||
|
||
const cookieName = "fs_token"
|
||
|
||
func Auth(token string) echo.MiddlewareFunc {
|
||
if token == "" {
|
||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||
return func(c echo.Context) error {
|
||
return next(c)
|
||
}
|
||
}
|
||
}
|
||
|
||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||
return func(c echo.Context) error {
|
||
// 1. Authorization header(API 调用,首选)
|
||
auth := c.Request().Header.Get("Authorization")
|
||
if len(auth) >= 7 && strings.HasPrefix(auth, "Bearer ") &&
|
||
subtle.ConstantTimeCompare([]byte(auth[7:]), []byte(token)) == 1 {
|
||
setAuthCookie(c, token)
|
||
return next(c)
|
||
}
|
||
// 2. Cookie(<img>/<video> 等浏览器自动携带)
|
||
if ck, err := c.Cookie(cookieName); err == nil &&
|
||
subtle.ConstantTimeCompare([]byte(ck.Value), []byte(token)) == 1 {
|
||
return next(c)
|
||
}
|
||
// 3. 查询参数(兼容旧版,可后续移除)
|
||
if qt := c.QueryParam("token"); qt != "" &&
|
||
subtle.ConstantTimeCompare([]byte(qt), []byte(token)) == 1 {
|
||
setAuthCookie(c, token)
|
||
return next(c)
|
||
}
|
||
return c.JSON(http.StatusUnauthorized, map[string]string{
|
||
"error": "unauthorized",
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
// setAuthCookie 首次认证成功后设置 Cookie(供 <img> 等浏览器请求自动携带)
|
||
func setAuthCookie(c echo.Context, token string) {
|
||
c.SetCookie(&http.Cookie{
|
||
Name: cookieName,
|
||
Value: token,
|
||
Path: "/",
|
||
MaxAge: int(24 * time.Hour / time.Second),
|
||
HttpOnly: true,
|
||
Secure: c.Request().TLS != nil,
|
||
SameSite: http.SameSiteLaxMode,
|
||
})
|
||
}
|