82 lines
1.8 KiB
Go
82 lines
1.8 KiB
Go
package common
|
||
|
||
import (
|
||
"context"
|
||
"net/http"
|
||
"strings"
|
||
|
||
"github.com/gogf/gf/v2/net/ghttp"
|
||
)
|
||
|
||
var publicPaths = []string{
|
||
"/system-config/login",
|
||
}
|
||
|
||
// CheckTokenFingerprint 由 kb/service 注入,避免 common → service 循环依赖
|
||
var CheckTokenFingerprint func(ctx context.Context, fp string) bool
|
||
|
||
func Auth(r *ghttp.Request) {
|
||
path := r.URL.Path
|
||
|
||
// 公开路径(精确匹配)
|
||
for _, p := range publicPaths {
|
||
if path == p {
|
||
r.Middleware.Next()
|
||
return
|
||
}
|
||
}
|
||
|
||
// workspace 源文件前缀放行(浏览器下载/预览请求不带 Authorization)
|
||
if strings.HasPrefix(path, "/workspace/") {
|
||
r.Middleware.Next()
|
||
return
|
||
}
|
||
|
||
// 前端静态资源放行:仅 GET / 与 GET /assets/*(hash 路由下 SPA 只请求这两个路径)
|
||
if r.Method == http.MethodGet && (path == "/" || strings.HasPrefix(path, "/assets/")) {
|
||
r.Middleware.Next()
|
||
return
|
||
}
|
||
|
||
auth := r.Header.Get("Authorization")
|
||
if auth == "" || !strings.HasPrefix(auth, "Bearer ") {
|
||
r.Response.WriteJson(ghttp.DefaultHandlerResponse{
|
||
Code: http.StatusUnauthorized,
|
||
Message: "未登录或登录已过期",
|
||
})
|
||
r.Exit()
|
||
return
|
||
}
|
||
|
||
claims, err := ParseToken(auth[7:])
|
||
if err != nil {
|
||
r.Response.WriteJson(ghttp.DefaultHandlerResponse{
|
||
Code: http.StatusUnauthorized,
|
||
Message: "登录已过期,请重新登录",
|
||
})
|
||
r.Exit()
|
||
return
|
||
}
|
||
|
||
// 指纹校验:访问令牌被重新生成后,旧会话立即失效
|
||
if CheckTokenFingerprint != nil && !CheckTokenFingerprint(r.Context(), claims.TokenFp) {
|
||
r.Response.WriteJson(ghttp.DefaultHandlerResponse{
|
||
Code: http.StatusUnauthorized,
|
||
Message: "访问令牌已变更,请重新登录",
|
||
})
|
||
r.Exit()
|
||
return
|
||
}
|
||
|
||
r.SetCtxVar("role", claims.Role)
|
||
r.Middleware.Next()
|
||
}
|
||
|
||
func GetRole(r *ghttp.Request) string {
|
||
v := r.GetCtxVar("role")
|
||
if v == nil {
|
||
return ""
|
||
}
|
||
return v.String()
|
||
}
|