refactor(auth): modularize auth plugin with physical subpackages and decoupled services

This commit is contained in:
ryan
2026-09-03 09:12:44 +08:00
parent 2124bce7ca
commit 4407589b62
51 changed files with 3859 additions and 2915 deletions
+52 -47
View File
@@ -8,6 +8,9 @@ import (
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/core/extpoints"
"Wavelet/plugins/domain/auth/controller"
"Wavelet/plugins/domain/auth/dao"
"Wavelet/plugins/domain/auth/service"
"context"
"embed"
"reflect"
@@ -83,39 +86,60 @@ func (p *Plugin) DeclareConfig() []core.ConfigBinding {
// Apply registers the auth migrations, services, routes, and settings into the Context.
func (p *Plugin) Apply(ctx *core.Context) error {
var cfg SessionConfig
if err := ctx.Config().Bind("app", &cfg); err == nil {
SetSessionConfig(cfg)
if cfg.SessionSecret != "" {
SetCapSecret([]byte(cfg.SessionSecret))
if err := ctx.Config().Bind("app", &cfg); err != nil {
cfg = SessionConfig{
SessionCookieName: "wavelet_session",
SessionAge: 86400,
SessionHTTPOnly: true,
}
}
core.Bind[contracts.DBService](ctx, setDBService)
core.Bind[contracts.CacheService](ctx, setCacheService)
core.Bind[contracts.LimiterService](ctx, setLimiterService)
d := dao.New(nil, nil, nil)
core.Bind[contracts.DBService](ctx, d.SetDBService)
core.Bind[contracts.CacheService](ctx, d.SetCacheService)
core.Bind[contracts.LimiterService](ctx, d.SetLimiterService)
ctx.OnDispose(func() error {
setDBService(nil)
setCacheService(nil)
setLimiterService(nil)
d.SetDBService(nil)
d.SetCacheService(nil)
d.SetLimiterService(nil)
return nil
})
var capSecret []byte
if cfg.SessionSecret != "" {
capSecret = []byte(cfg.SessionSecret)
}
svc := service.New(d, cfg, capSecret)
if p.authSvc != nil {
// Custom injected auth service override
core.Provide[contracts.AuthService](ctx, p.authSvc)
} else {
core.Provide[contracts.AuthService](ctx, svc.AuthSvc)
}
if p.authRegistry != nil {
core.Provide[contracts.AuthRegistry](ctx, p.authRegistry)
} else {
core.Provide[contracts.AuthRegistry](ctx, svc.AuthRegistry)
}
ctrl := controller.New(svc)
setDefaultRuntime(d, svc, ctrl)
// Register CaptchaService
captchaSvc := service.NewCaptchaService(
svc.CapManager,
func(scope string) any { return ctrl.VerifyCaptcha(scope) },
ctrl.Captcha.Challenge,
ctrl.Captcha.Redeem,
)
core.Provide[contracts.CaptchaService](ctx, captchaSvc)
// 1. Register migrations
ctx.Migrations().Register("auth", authMigrations)
// 2. Initialize and provide AuthService, AuthRegistry & CaptchaService
if p.authSvc == nil {
p.authSvc = newAuthService()
}
if p.authRegistry == nil {
p.authRegistry = newAuthRegistry()
}
core.Provide[contracts.AuthService](ctx, p.authSvc)
core.Provide[contracts.AuthRegistry](ctx, p.authRegistry)
core.Provide[contracts.CaptchaService](ctx, captchaService{})
// 2.1 Register Public / Auth Whitelist Endpoints
// 2. Register Public / Auth Whitelist Endpoints
publicEndpoints := []string{
"/api/v1/oauth/sources",
"/api/v1/oauth/login",
@@ -131,30 +155,11 @@ func (p *Plugin) Apply(ctx *core.Context) error {
"/api/healthz",
"/metrics",
}
RegisterWhitelist(publicEndpoints...)
ctrl.RegisterWhitelist(publicEndpoints...)
ctx.Router().RegisterWhitelist(publicEndpoints...)
// 3. Register HTTP Routes
oauthGroup := ctx.Router().Group("/api/v1/oauth")
{
oauthGroup.GET("/sources", GetLoginSources)
oauthGroup.GET("/login", GetLoginURL)
oauthGroup.GET("/:source/authorize", Authorize)
oauthGroup.GET("/logout", Logout)
oauthGroup.POST("/callback", Callback)
oauthGroup.GET("/user-info", LoginRequired(), UserInfo)
oauthGroup.GET("/external-accounts", LoginRequired(), ListExternalAccounts)
oauthGroup.POST("/external-accounts/:id/delete", LoginRequired(), DeleteExternalAccount)
}
ctx.Router().GET("/api/v1/user-info", LoginRequired(), UserInfo)
// 3.1 Register CAPTCHA HTTP Routes
capGroup := ctx.Router().Group("/api/v1/cap")
{
capGroup.GET("/challenge", Challenge)
capGroup.POST("/challenge", Challenge)
capGroup.POST("/redeem", Redeem)
}
ctrl.RegisterRoutes(ctx.Router())
// 4. Register Settings Schemas
const (
@@ -193,17 +198,17 @@ func (p *Plugin) Apply(ctx *core.Context) error {
// 5. Register Event Listeners for domain events
ctx.Events().On(contracts.EventTopicUserStatusChanged, func(c context.Context, e contracts.UserStatusChangedEvent) error {
InvalidateCachedUser(c, e.UserID)
svc.DAO.InvalidateCachedUser(c, e.UserID)
return nil
})
ctx.Events().On(contracts.EventTopicUserDeleted, func(c context.Context, e contracts.UserDeletedEvent) error {
InvalidateCachedUser(c, e.TargetUserID)
svc.DAO.InvalidateCachedUser(c, e.TargetUserID)
return nil
})
ctx.Events().On(contracts.EventTopicConfigChanged, func(_ any) {
InvalidateCapRuntimeSettings()
svc.CapSettings.Invalidate()
})
return nil