新增 4 项可配置站点设置(DB持久化+内存缓存,即时生效): - site.brand 品牌名(页面标题/页脚/管理面板,默认 MetaLab) - site.framework 框架名(页脚标识,默认 MetaZone) - site.copyright_start 版权起始年(页脚,默认 2024) - registration.enabled 注册开关(关闭后禁止新用户注册,默认 true) 实现方式: - InjectSiteInfo 中间件:全局注入 Brand/Framework/CopyrightStart 到 gin.Context - BuildPageData 读取 context,所有 SSR 页面自动获取站点信息 - AuthService.Register 最先检查 IsRegistrationEnabled() - 管理后台新增「基本设置」+「注册设置」区块,文本输入手动保存 + Toggle 即时生效
99 lines
2.7 KiB
Go
99 lines
2.7 KiB
Go
package controller
|
||
|
||
import (
|
||
"net/http"
|
||
|
||
"metazone.cc/metalab/internal/common"
|
||
"metazone.cc/metalab/internal/model"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// CheckEmail 检查邮箱是否已注册
|
||
func (ac *AuthController) CheckEmail(c *gin.Context) {
|
||
var req model.CheckEmailRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
common.Error(c, http.StatusBadRequest, "请提供有效的邮箱地址")
|
||
return
|
||
}
|
||
|
||
exists, err := ac.authService.CheckEmail(req.Email)
|
||
if err != nil {
|
||
common.Error(c, http.StatusInternalServerError, "检查失败")
|
||
return
|
||
}
|
||
|
||
common.Ok(c, gin.H{"exists": exists})
|
||
}
|
||
|
||
// Register 注册 API
|
||
func (ac *AuthController) Register(c *gin.Context) {
|
||
var req model.RegisterRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
common.Error(c, http.StatusBadRequest, "请检查输入:"+err.Error())
|
||
return
|
||
}
|
||
|
||
// 注册 IP 限流:1 分钟 5 次
|
||
regResult, recordReg := ac.rateLimiter.AllowIP(clientIP(c) + ":register")
|
||
if regResult.Blocked {
|
||
common.Error(c, http.StatusTooManyRequests, "注册请求过于频繁,请稍后重试")
|
||
return
|
||
}
|
||
|
||
accessToken, refreshToken, user, err := ac.authService.Register(req, clientIP(c))
|
||
if err != nil {
|
||
if recordReg != nil {
|
||
recordReg()
|
||
}
|
||
switch err {
|
||
case common.ErrEmailExists:
|
||
common.Error(c, http.StatusConflict, "该邮箱已注册")
|
||
case common.ErrWeakPassword:
|
||
common.Error(c, http.StatusBadRequest, err.Error())
|
||
case common.ErrRegistrationDisabled:
|
||
common.Error(c, http.StatusForbidden, "注册功能已关闭")
|
||
default:
|
||
common.Error(c, http.StatusInternalServerError, "注册失败,请稍后重试")
|
||
}
|
||
return
|
||
}
|
||
|
||
common.SetAuthCookies(c, accessToken, refreshToken, req.RememberMe, ac.cfg)
|
||
|
||
common.OkWithMessage(c, user, "注册成功!欢迎加入 MetaLab")
|
||
}
|
||
|
||
// Logout 退出登录:清除所有认证 Cookie
|
||
func (ac *AuthController) Logout(c *gin.Context) {
|
||
common.ClearAuthCookies(c, ac.cfg)
|
||
common.OkMessage(c, "已退出登录")
|
||
}
|
||
|
||
// RefreshToken 用 refresh token 换取新的 access token
|
||
func (ac *AuthController) RefreshToken(c *gin.Context) {
|
||
refreshToken, err := c.Cookie(common.RefreshCookieName)
|
||
if err != nil {
|
||
common.Error(c, http.StatusUnauthorized, "请重新登录")
|
||
return
|
||
}
|
||
|
||
accessToken, _, err := ac.tokenService.RefreshAccessToken(refreshToken)
|
||
if err != nil {
|
||
common.ClearAuthCookies(c, ac.cfg)
|
||
switch err {
|
||
case common.ErrTokenExpired, common.ErrTokenRevoked:
|
||
common.Error(c, http.StatusUnauthorized, "登录凭证已失效,请重新登录")
|
||
case common.ErrUserBanned:
|
||
common.Error(c, http.StatusForbidden, "账号已被封禁")
|
||
default:
|
||
common.Error(c, http.StatusUnauthorized, "请重新登录")
|
||
}
|
||
return
|
||
}
|
||
|
||
common.SetAccessCookie(c, accessToken, ac.cfg)
|
||
|
||
common.Ok(c, nil)
|
||
}
|