126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
package user
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"github.com/saas-mingyang/mingyang-admin-common/i18n"
|
||
"mingyang-admin-app-api/internal/svc"
|
||
"mingyang-admin-app-api/internal/types"
|
||
"mingyang-admin-app-rpc/types/app"
|
||
"net/http"
|
||
"runtime"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/zeromicro/go-zero/core/logx"
|
||
)
|
||
|
||
type LogoutLogic struct {
|
||
logx.Logger
|
||
ctx context.Context
|
||
svcCtx *svc.ServiceContext
|
||
}
|
||
|
||
func NewLogoutLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogoutLogic {
|
||
return &LogoutLogic{
|
||
Logger: logx.WithContext(ctx),
|
||
ctx: ctx,
|
||
svcCtx: svcCtx,
|
||
}
|
||
}
|
||
|
||
// Logout 在API层添加调用栈信息
|
||
func (l *LogoutLogic) Logout() (resp *types.BaseMsgResp, err error) {
|
||
// 打印调用栈
|
||
buf := make([]byte, 1024)
|
||
n := runtime.Stack(buf, false)
|
||
l.Logger.Infof("Logout call stack:\n%s", buf[:n])
|
||
|
||
token := l.getTokenFromContext()
|
||
l.Infof("Starting Logout RPC call at: %v", time.Now())
|
||
|
||
// 记录goroutine ID
|
||
goID := getGoroutineID()
|
||
l.Logger.Infof("Goroutine ID: %d", goID)
|
||
|
||
_, err = l.svcCtx.AppRpc.LogoutUser(l.ctx, &app.UserToken{
|
||
AccessToken: token,
|
||
UserId: l.getUserIDFromContext(),
|
||
})
|
||
|
||
l.Logger.Infof("Finished Logout RPC call at: %v", time.Now())
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &types.BaseMsgResp{Msg: l.svcCtx.Trans.Trans(l.ctx, i18n.Success)}, nil
|
||
}
|
||
|
||
// 获取goroutine ID
|
||
func getGoroutineID() uint64 {
|
||
b := make([]byte, 64)
|
||
b = b[:runtime.Stack(b, false)]
|
||
b = bytes.TrimPrefix(b, []byte("goroutine "))
|
||
b = b[:bytes.IndexByte(b, ' ')]
|
||
n, _ := strconv.ParseUint(string(b), 10, 64)
|
||
return n
|
||
}
|
||
|
||
// 从上下文中获取 Token
|
||
func (l *LogoutLogic) getTokenFromContext() string {
|
||
// 尝试不同的 key 从上下文中获取 Token
|
||
keys := []string{"token", "access_token", "jwt_token", "auth_token"}
|
||
|
||
for _, key := range keys {
|
||
if token, ok := l.ctx.Value(key).(string); ok && token != "" {
|
||
return l.cleanToken(token)
|
||
}
|
||
}
|
||
return ""
|
||
}
|
||
|
||
// 清理 Token 字符串,移除 "Bearer " 前缀
|
||
func (l *LogoutLogic) cleanToken(token string) string {
|
||
if token == "" {
|
||
return ""
|
||
}
|
||
token = strings.TrimSpace(token)
|
||
// 移除 "Bearer " 前缀
|
||
if strings.HasPrefix(strings.ToLower(token), "bearer ") {
|
||
token = token[7:]
|
||
}
|
||
return token
|
||
}
|
||
|
||
// 从 Authorization Header 中提取 Token
|
||
func (l *LogoutLogic) extractTokenFromAuthHeader(ctx context.Context) string {
|
||
// 尝试从请求上下文获取 Request 对象
|
||
if req, ok := ctx.Value("http_request").(*http.Request); ok {
|
||
authHeader := req.Header.Get("Authorization")
|
||
if authHeader != "" {
|
||
return l.cleanToken(authHeader)
|
||
}
|
||
}
|
||
return ""
|
||
}
|
||
|
||
// 从上下文中获取用户ID
|
||
func (l *LogoutLogic) getUserIDFromContext() uint64 {
|
||
// 在AuthMiddleware中,我们将用户ID放入了context
|
||
if userID, ok := l.ctx.Value("userId").(uint64); ok {
|
||
return userID
|
||
}
|
||
return 0
|
||
}
|
||
|
||
// 获取 Token 过期时间
|
||
func (l *LogoutLogic) getTokenExpireTime(token string) (time.Time, error) {
|
||
// 使用 JWTManager 验证并获取 Claims
|
||
claims, err := l.svcCtx.AppRpc.AuthToken(l.ctx, &app.AuthReq{Token: token})
|
||
if err != nil {
|
||
return time.Time{}, err
|
||
}
|
||
return claims.Claims.ExpiresAt.Timestamp.AsTime(), nil
|
||
}
|