feat(auth): add logout functionality

- Implement LogoutHandler to handle user logout requests
- Add DeleteTokenInfo and GetUserIDFromToken functions to auth module
- Update README.md with logout endpoint documentation
This commit is contained in:
2026-03-03 23:02:52 +08:00
parent 1c347d14b6
commit 232e87ae36
4 changed files with 83 additions and 3 deletions

View File

@@ -77,7 +77,7 @@ All API responses are returned in JSON format:
---
### 1. Register User
### Register User
**Endpoint:** `/register`
**Method:** POST
@@ -122,7 +122,7 @@ X-Timestamp: 1704067200000
---
### 2. Login
### Login
**Endpoint:** `/login`
**Method:** POST
@@ -166,6 +166,32 @@ X-Timestamp: 1704067200000
---
### Logout
**Endpoint:** `/logout`
**Method:** GET
**Auth Required:** Yes (token)
**Request Headers:**
```
X-Token: your_token
X-Timestamp: 1704067200000
```
| Header | Type | Required | Description |
|--------|------|----------|-------------|
| X-Token | string | Yes | Authentication token |
| X-Timestamp | int64 | Yes | Client timestamp in milliseconds |
**Response:**
```json
{
"success": true,
"message": "Logout successful"
}
```
---
### 3. Create frpc Instance
**Endpoint:** `/frpcAct/instanceMgr/create`

26
auth.go
View File

@@ -106,7 +106,7 @@ func GetTokenInfo(userID int) (*TokenInfo, error) {
tokenInfo, exists := tokenMap[userID]
if !exists {
return nil, fmt.Errorf("Token not found for userID %d", userID)
}
return tokenInfo, nil
@@ -199,3 +199,27 @@ func ValidateTimeStamp(header http.Header) bool {
}
return true
}
func GetUserIDFromToken(token string) (int, error) {
userID, err := extractUserIDFromToken(token)
if err != nil {
return 0, fmt.Errorf("Failed to extract userID from token: %w", err)
}
return userID, nil
}
func DeleteTokenInfo(userID int) error {
tokenMux.Lock()
defer tokenMux.Unlock()
delete(tokenMap, userID)
postLog.Debug(fmt.Sprintf("[DeleteTokenInfo] Removed token for userID %d", userID))
return nil
}
func GetUsernameByID(userID int) (string) {
user, err := GetUserByID(userID)
if err != nil {
return ""
}
return user.Username
}

View File

@@ -10,6 +10,7 @@ func setupRoutes() {
postLog.Info("Setting up routes...")
http.HandleFunc("/register", RegisterHandler)
http.HandleFunc("/login", LoginHandler)
http.HandleFunc("/logout", LogoutHandler)
http.HandleFunc("/frpcAct/instanceMgr/create", CreateInstanceHandler)
http.HandleFunc("/frpcAct/instanceMgr/list", ListInstancesHandler)

View File

@@ -159,3 +159,32 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
})
postLog.Info(fmt.Sprintf("[LoginHandler] User \"%s\" Login successful", req.Username))
}
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
postLog.Warning(fmt.Sprintf("[LogoutHandler] Invalid request method: %s", r.Method))
return
}
if !ValidateTimeStamp(r.Header) {
SendErrorResponse(w, http.StatusBadRequest, "Invalid or missing X-Timestamp in header")
return
}
userID, err := GetUserIDFromToken(r.Header.Get("X-Token"))
if err != nil {
SendErrorResponse(w, http.StatusUnauthorized, "Invalid or missing token")
postLog.Warning(fmt.Sprintf("[LogoutHandler] Invalid or missing token: %v", err))
return
}
if err := DeleteTokenInfo(userID); err != nil {
SendErrorResponse(w, http.StatusInternalServerError, "Failed to logout")
postLog.Error(fmt.Sprintf("[LogoutHandler] Failed to logout user [%d]%s: %v", userID, GetUsernameByID(userID), err))
return
}
SendSuccessResponse(w, "Logout successful", nil)
postLog.Info(fmt.Sprintf("[LogoutHandler] User [%d]%s Logout successful", userID, GetUsernameByID(userID)))
}