From 84c61efeef4d94cd8ef4272ff065bf1bd302ea7c Mon Sep 17 00:00:00 2001 From: yanzuoguang Date: Fri, 7 Nov 2025 21:53:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(authorization):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=BA=AB=E4=BB=BD=E9=AA=8C=E8=AF=81=E4=B8=AD=E9=97=B4=E4=BB=B6?= =?UTF-8?q?=E5=92=8C=E8=A7=92=E8=89=B2=E6=9D=A1=E4=BB=B6=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E5=8A=9F=E8=83=BD-=20=E6=96=B0=E5=A2=9E=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E4=B8=AD=E9=97=B4=E4=BB=B6=E7=BB=84=E4=BB=B6=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=B7=AF=E5=BE=84=E5=89=8D=E7=BC=80=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E5=92=8C=E8=AF=B7=E6=B1=82=E5=A4=84=E7=90=86=E7=AE=A1=E9=81=93?= =?UTF-8?q?=20-=20=E5=AE=9E=E7=8E=B0=E5=9F=BA=E4=BA=8E=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E7=9A=84URL=E5=9B=9E=E9=80=80?= =?UTF-8?q?=E8=B7=B3=E8=BD=AC=E6=9C=BA=E5=88=B6=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=E9=AA=8C=E8=AF=81=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E5=A4=9A=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E9=AA=8C=E8=AF=81=20-=20=E9=9B=86=E6=88=90?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=9C=8D=E5=8A=A1=E6=B3=A8=E5=86=8C=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E6=94=AF=E6=8C=81=E4=BB=8E=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E4=B8=AD=E8=8E=B7=E5=8F=96=E5=BD=93=E5=89=8D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=20-=20=E5=AE=9E=E7=8E=B0=E6=9C=AA=E8=AE=A4=E8=AF=81=E5=92=8C?= =?UTF-8?q?=E6=9C=AA=E6=8E=88=E6=9D=83=E7=8A=B6=E6=80=81=E7=9A=84HTTP?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E5=A4=84=E7=90=86=20-=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E8=AE=A4=E8=AF=81=E5=A4=B1=E8=B4=A5=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E9=87=8D=E5=AE=9A=E5=90=91URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/authorization/auth_middleware.go | 77 +++++++++++++++++++ .../platform/authorization/role_condition.go | 20 +++++ .../platform/authorization/user_service.go | 23 ++++++ 3 files changed, 120 insertions(+) create mode 100644 32-platform/platform/authorization/auth_middleware.go create mode 100644 32-platform/platform/authorization/role_condition.go create mode 100644 32-platform/platform/authorization/user_service.go diff --git a/32-platform/platform/authorization/auth_middleware.go b/32-platform/platform/authorization/auth_middleware.go new file mode 100644 index 0000000..d2acbdf --- /dev/null +++ b/32-platform/platform/authorization/auth_middleware.go @@ -0,0 +1,77 @@ +package authorization + +import ( + "net/http" + "platform/authorization/identity" + "platform/config" + "platform/http/handing" + "platform/pipeline" + "regexp" + "strings" +) + +func NewAuthComponent(prefix string, condition identity.AuthorizationCondition, requestHandlers ...interface{}) *AuthMiddlewareComponent { + var entries []handing.HandlerEntry + for _, handler := range requestHandlers { + entries = append(entries, handing.HandlerEntry{Prefix: prefix, Handler: handler}) + } + router := handing.NewRouter(entries...) + + return &AuthMiddlewareComponent{ + prefix: "/" + prefix, + condition: condition, + RequestPipeline: pipeline.CreatePipeline(router), + fallbacks: map[*regexp.Regexp]string{}, + } +} + +type AuthMiddlewareComponent struct { + prefix string + condition identity.AuthorizationCondition + pipeline.RequestPipeline + config.Configuration + authFailUrl string + fallbacks map[*regexp.Regexp]string +} + +func (c *AuthMiddlewareComponent) Init() { + c.authFailUrl, _ = c.Configuration.GetString("authorization:failUrl") +} + +func (c *AuthMiddlewareComponent) ImplementsProcessRequestWithServices() {} + +func (c *AuthMiddlewareComponent) ProcessRequestWithService(context *pipeline.ComponentContext, next func(*pipeline.ComponentContext), user identity.User) { + // 匹配前缀 + if strings.HasPrefix(context.Request.URL.Path, c.prefix) { + for expr, target := range c.fallbacks { + // 正则表达式匹配,则跳转URL + if expr.MatchString(context.Request.URL.Path) { + http.Redirect(context.ResponseWriter, context.Request, target, http.StatusSeeOther) + return + } + } + if c.condition.Validate(user) { + // 验证通过,则继续处理 + err := c.RequestPipeline.ProcessRequest(context.Request, context.ResponseWriter) + if err != nil { + context.Error(err) + return + } + } else if c.authFailUrl != "" { + http.Redirect(context.ResponseWriter, context.Request, c.authFailUrl, http.StatusSeeOther) + } else if user.IsAuthenticated() { + context.ResponseWriter.WriteHeader(http.StatusForbidden) + } else { + context.ResponseWriter.WriteHeader(http.StatusUnauthorized) + } + } else { + next(context) + } +} + +func (c *AuthMiddlewareComponent) AddFallback(target string, patterns ...string) *AuthMiddlewareComponent { + for _, p := range patterns { + c.fallbacks[regexp.MustCompile(p)] = target + } + return c +} diff --git a/32-platform/platform/authorization/role_condition.go b/32-platform/platform/authorization/role_condition.go new file mode 100644 index 0000000..e91795f --- /dev/null +++ b/32-platform/platform/authorization/role_condition.go @@ -0,0 +1,20 @@ +package authorization + +import "platform/authorization/identity" + +func NewRoleCondition(roles ...string) identity.AuthorizationCondition { + return &roleCondition{allowedRoles: roles} +} + +type roleCondition struct { + allowedRoles []string +} + +func (c *roleCondition) Validate(user identity.User) bool { + for _, role := range c.allowedRoles { + if user.InRole(role) { + return true + } + } + return false +} diff --git a/32-platform/platform/authorization/user_service.go b/32-platform/platform/authorization/user_service.go new file mode 100644 index 0000000..1ef6da6 --- /dev/null +++ b/32-platform/platform/authorization/user_service.go @@ -0,0 +1,23 @@ +package authorization + +import ( + "platform/authorization/identity" + "platform/services" + "platform/sessions" +) + +func RegisterDefaultUserService() { + err := services.AddScoped(func(session sessions.Session, store identity.UserStore) identity.User { + userId, found := session.GetValue(UserSessionKey).(int) + if found { + user, userFound := store.GetUserById(userId) + if userFound { + return user + } + } + return identity.UnauthenticatedUser + }) + if err != nil { + panic(err) + } +}