- 后端:新增 refresh_token 模型与服务,登录签发 refresh token,支持静默续期与登出撤销 (backend/internal/model/refresh_token.go, backend/internal/service/auth/refresh.go, auth_controller/auth_service/dto/router/jwt 配套改动) - 前端:登录页改为「记住登录」(只持久化引导令牌与用户名,不落盘密码),401 自动刷新并重试原请求 (stores/user.js, api/request.js, api/auth.js, main.js, Login.vue 配套改动) - 部署:已在容器中验证运行(镜像构建于 2026-11-03 00:50,服务 healthy) - 安全:仓库内无任何 .env/证书/密钥文件变更
This commit is contained in:
1 parent
4bf7fb6e5c
commit
a01b89f942
13 files changed
+531
-208
No files matched your search
@@ -2,6 +2,7 @@ package auth
|
||||
|
||||
import (
|
||||
"backend/config"
|
||||
"backend/internal/dto"
|
||||
authservice "backend/internal/service/auth"
|
||||
"backend/utils"
|
||||
"net/http"
|
||||
@@ -24,6 +25,23 @@ func NewAuthController(db *gorm.DB, cfg *config.Config) *AuthController {
|
||||
}
|
||||
}
|
||||
|
||||
// buildLoginResponse 把 service 结果组装成响应体(登录与刷新同构) // Logan.Li
|
||||
func buildLoginResponse(result *authservice.LoginResult) dto.LoginResponse {
|
||||
return dto.LoginResponse{
|
||||
Token: result.AccessToken,
|
||||
ExpiresIn: utils.AccessTokenTTLSeconds(),
|
||||
RefreshToken: result.RefreshToken,
|
||||
RefreshExpiresAt: result.RefreshExpiresAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||
UserInfo: dto.UserInfoResponse{
|
||||
ID: result.User.ID,
|
||||
Username: result.User.Username,
|
||||
Email: result.User.Email,
|
||||
Avatar: result.User.Avatar,
|
||||
Role: result.User.Role,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Login 管理员登录(成功/失败均记审计) // Logan.Li
|
||||
func (ctrl *AuthController) Login(c *gin.Context) {
|
||||
var req struct {
|
||||
@@ -35,7 +53,7 @@ func (ctrl *AuthController) Login(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := ctrl.authService.Login(req)
|
||||
result, err := ctrl.authService.Login(dto.LoginRequest{Username: req.Username, Password: req.Password}, c.ClientIP(), c.Request.UserAgent())
|
||||
if err != nil {
|
||||
utils.LogAuthAction(ctrl.db, c, "login", req.Username, err.Error(), "failure")
|
||||
c.JSON(http.StatusOK, gin.H{"code": 1, "message": utils.InternalMsg(err)})
|
||||
@@ -43,7 +61,34 @@ func (ctrl *AuthController) Login(c *gin.Context) {
|
||||
}
|
||||
|
||||
utils.LogAuthAction(ctrl.db, c, "login", req.Username, "登录成功", "success")
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "登录成功", "data": result})
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "登录成功", "data": buildLoginResponse(result)})
|
||||
}
|
||||
|
||||
// Refresh 用刷新令牌换取新的访问令牌(一次性轮换,重放会撤销全部会话) // Logan.Li
|
||||
func (ctrl *AuthController) Refresh(c *gin.Context) {
|
||||
var req dto.RefreshRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "请求参数错误: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := ctrl.authService.Refresh(req.RefreshToken, c.ClientIP(), c.Request.UserAgent())
|
||||
if err != nil {
|
||||
utils.LogAuthAction(ctrl.db, c, "refresh", "-", err.Error(), "failure")
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": utils.InternalMsg(err)})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "刷新成功", "data": buildLoginResponse(result)})
|
||||
}
|
||||
|
||||
// Logout 登出:撤销刷新令牌(幂等,未带令牌也返回成功) // Logan.Li
|
||||
func (ctrl *AuthController) Logout(c *gin.Context) {
|
||||
var req dto.LogoutRequest
|
||||
_ = c.ShouldBindJSON(&req) // 允许空 body:前端丢了本地令牌也要能登出 // Logan.Li
|
||||
ctrl.authService.Revoke(req.RefreshToken)
|
||||
utils.LogAuthAction(ctrl.db, c, "logout", "-", "退出登录", "success")
|
||||
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "已退出登录"})
|
||||
}
|
||||
|
||||
// Me 获取当前登录用户信息 // Logan.Li
|
||||
@@ -72,7 +117,10 @@ func (ctrl *AuthController) ChangePassword(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := ctrl.authService.ChangePassword(userID.(uint), req); err != nil {
|
||||
if err := ctrl.authService.ChangePassword(userID.(uint), dto.ChangePasswordRequest{
|
||||
OldPassword: req.OldPassword,
|
||||
NewPassword: req.NewPassword,
|
||||
}); err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"code": 1, "message": utils.InternalMsg(err)})
|
||||
return
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user