fix: resolve user dashboard field mapping and session consistency
Added JSON tags to the User struct to match frontend expectations and excluded sensitive fields. Updated session management to include and persist DisplayName. Unified user field names (using display_name) across backend, sessions, and frontend UI.
This commit is contained in:
@@ -244,13 +244,13 @@ type ModelConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID int `db:"id"`
|
ID int `db:"id" json:"id"`
|
||||||
Username string `db:"username"`
|
Username string `db:"username" json:"username"`
|
||||||
PasswordHash string `db:"password_hash"`
|
PasswordHash string `db:"password_hash" json:"-"`
|
||||||
DisplayName *string `db:"display_name"`
|
DisplayName *string `db:"display_name" json:"display_name"`
|
||||||
Role string `db:"role"`
|
Role string `db:"role" json:"role"`
|
||||||
MustChangePassword bool `db:"must_change_password"`
|
MustChangePassword bool `db:"must_change_password" json:"must_change_password"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientToken struct {
|
type ClientToken struct {
|
||||||
|
|||||||
@@ -83,25 +83,21 @@ func (s *Server) handleLogin(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := s.sessions.CreateSession(user.Username, user.Role)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to create session"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
displayName := user.Username
|
displayName := user.Username
|
||||||
if user.DisplayName != nil {
|
if user.DisplayName != nil {
|
||||||
displayName = *user.DisplayName
|
displayName = *user.DisplayName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token, err := s.sessions.CreateSession(user.Username, displayName, user.Role)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, ErrorResponse("Failed to create session"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, SuccessResponse(gin.H{
|
c.JSON(http.StatusOK, SuccessResponse(gin.H{
|
||||||
"token": token,
|
"token": token,
|
||||||
"must_change_password": user.MustChangePassword,
|
"must_change_password": user.MustChangePassword,
|
||||||
"user": gin.H{
|
"user": user,
|
||||||
"username": user.Username,
|
|
||||||
"name": displayName,
|
|
||||||
"role": user.Role,
|
|
||||||
},
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,8 +112,9 @@ func (s *Server) handleAuthStatus(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, SuccessResponse(gin.H{
|
c.JSON(http.StatusOK, SuccessResponse(gin.H{
|
||||||
"authenticated": true,
|
"authenticated": true,
|
||||||
"user": gin.H{
|
"user": gin.H{
|
||||||
"username": session.Username,
|
"username": session.Username,
|
||||||
"role": session.Role,
|
"role": session.Role,
|
||||||
|
"display_name": session.DisplayName,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Role string `json:"role"`
|
DisplayName string `json:"display_name"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
Role string `json:"role"`
|
||||||
ExpiresAt time.Time `json:"expires_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
SessionID string `json:"session_id"`
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionManager struct {
|
type SessionManager struct {
|
||||||
@@ -29,10 +30,11 @@ type SessionManager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type sessionPayload struct {
|
type sessionPayload struct {
|
||||||
SessionID string `json:"session_id"`
|
SessionID string `json:"session_id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Role string `json:"role"`
|
DisplayName string `json:"display_name"`
|
||||||
Exp int64 `json:"exp"`
|
Role string `json:"role"`
|
||||||
|
Exp int64 `json:"exp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSessionManager(secret []byte, ttl time.Duration) *SessionManager {
|
func NewSessionManager(secret []byte, ttl time.Duration) *SessionManager {
|
||||||
@@ -43,30 +45,32 @@ func NewSessionManager(secret []byte, ttl time.Duration) *SessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SessionManager) CreateSession(username, role string) (string, error) {
|
func (m *SessionManager) CreateSession(username, displayName, role string) (string, error) {
|
||||||
sessionID := uuid.New().String()
|
sessionID := uuid.New().String()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
expiresAt := now.Add(m.ttl)
|
expiresAt := now.Add(m.ttl)
|
||||||
|
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
m.sessions[sessionID] = Session{
|
m.sessions[sessionID] = Session{
|
||||||
Username: username,
|
Username: username,
|
||||||
Role: role,
|
DisplayName: displayName,
|
||||||
CreatedAt: now,
|
Role: role,
|
||||||
ExpiresAt: expiresAt,
|
CreatedAt: now,
|
||||||
SessionID: sessionID,
|
ExpiresAt: expiresAt,
|
||||||
|
SessionID: sessionID,
|
||||||
}
|
}
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
|
|
||||||
return m.createSignedToken(sessionID, username, role, expiresAt.Unix())
|
return m.createSignedToken(sessionID, username, displayName, role, expiresAt.Unix())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SessionManager) createSignedToken(sessionID, username, role string, exp int64) (string, error) {
|
func (m *SessionManager) createSignedToken(sessionID, username, displayName, role string, exp int64) (string, error) {
|
||||||
payload := sessionPayload{
|
payload := sessionPayload{
|
||||||
SessionID: sessionID,
|
SessionID: sessionID,
|
||||||
Username: username,
|
Username: username,
|
||||||
Role: role,
|
DisplayName: displayName,
|
||||||
Exp: exp,
|
Role: role,
|
||||||
|
Exp: exp,
|
||||||
}
|
}
|
||||||
|
|
||||||
payloadJSON, err := json.Marshal(payload)
|
payloadJSON, err := json.Marshal(payload)
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ class AuthManager {
|
|||||||
const userRoleElement = document.querySelector('.user-role');
|
const userRoleElement = document.querySelector('.user-role');
|
||||||
|
|
||||||
if (userNameElement && this.user) {
|
if (userNameElement && this.user) {
|
||||||
userNameElement.textContent = this.user.name || this.user.username || 'User';
|
userNameElement.textContent = this.user.display_name || this.user.username || 'User';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userRoleElement && this.user) {
|
if (userRoleElement && this.user) {
|
||||||
|
|||||||
Reference in New Issue
Block a user