HTTP API закрыт за вход через OIDC у Authelia
- шаг схемы закрывает поверхность, которую хранилище приносит открытой: собственную регистрацию, вход по паролю и одноразовый код — без этого закрытие приёма обходилось двумя запросами - продление сессии выключено, срок семь суток: иначе отзыв доступа у провайдера до сервиса не доходит никогда - файл записи отдаётся вошедшему по токену файла — пересмотр ADR-2026-08-12-file-link-open-but-not-logged
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/hook"
|
||||
)
|
||||
|
||||
// RefreshPath — адрес хранилища, которым сессия продлевает саму себя.
|
||||
const RefreshPath = "/api/collections/users/auth-refresh"
|
||||
|
||||
// BlockSessionRefresh закрывает продление сессии.
|
||||
//
|
||||
// Хранилище выдаёт сессию продлеваемой: предъявитель значения меняет его на
|
||||
// новое, с новым сроком, и делает это сколько угодно раз, никуда не входя. При
|
||||
// живом продлении срок жизни сессии перестаёт что-либо значить, а вместе с ним
|
||||
// перестаёт работать единственный канал, которым отзыв доступа у провайдера
|
||||
// доходит до сервиса, — сервис после входа к провайдеру не обращается.
|
||||
//
|
||||
// Решение владельца от 2026-08-12: продление выключено, цена — вход раз в
|
||||
// семь суток.
|
||||
func BlockSessionRefresh() *hook.Handler[*core.RequestEvent] {
|
||||
return &hook.Handler[*core.RequestEvent]{
|
||||
Id: "transcriberBlockSessionRefresh",
|
||||
Priority: apis.DefaultLoadAuthTokenMiddlewarePriority - 2,
|
||||
Func: func(e *core.RequestEvent) error {
|
||||
if e.Request.URL.Path == RefreshPath {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{
|
||||
"error": "Продление сессии выключено",
|
||||
})
|
||||
}
|
||||
|
||||
return e.Next()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SessionFromCookie перекладывает значение куки сессии в заголовок, которым
|
||||
// хранилище читает предъявленную сессию.
|
||||
//
|
||||
// Куки хранилище не читает вовсе — только заголовок `Authorization`. Браузер же
|
||||
// сам заголовка не шлёт, а своей страницы со скриптом у сервиса нет, поэтому
|
||||
// сессия предъявляется кукой, а способ проверки остаётся один.
|
||||
//
|
||||
// Предъявленный заголовок побеждает: иначе браузер с сессионной кукой получал
|
||||
// бы на собственных адресах хранилища не то, что предъявил.
|
||||
//
|
||||
// Слой стоит раньше проверки токена: тот идёт с приоритетом
|
||||
// DefaultLoadAuthTokenMiddlewarePriority и к этому моменту заголовок должен
|
||||
// быть на месте.
|
||||
func SessionFromCookie() *hook.Handler[*core.RequestEvent] {
|
||||
return &hook.Handler[*core.RequestEvent]{
|
||||
Id: "transcriberSessionFromCookie",
|
||||
Priority: apis.DefaultLoadAuthTokenMiddlewarePriority - 1,
|
||||
Func: func(e *core.RequestEvent) error {
|
||||
if e.Request.Header.Get("Authorization") != "" {
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
cookie, err := e.Request.Cookie(SessionCookieName)
|
||||
if err != nil || cookie.Value == "" {
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
e.Request.Header.Set("Authorization", cookie.Value)
|
||||
|
||||
return e.Next()
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user