Refactor login cookie handling to improve security and organization

- Consolidated cookie management into a new SendLoginCookies function, which sends access token, refresh token, and session ID cookies with appropriate security settings.
- Updated authback functions in the signin and oauth files to utilize the new SendLoginCookies function, enhancing code clarity and reducing duplication.
This commit is contained in:
Max 2025-09-18 10:10:58 +08:00
parent 54d7120626
commit 6f3a57cb33
4 changed files with 152 additions and 18 deletions

View file

@ -214,15 +214,8 @@ func authback(c *gin.Context) {
return
}
// Authorize Cookie
accessToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.AccessToken)
refreshToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.RefreshToken)
// Send Cookie
expires := time.Now().Add(time.Duration(loginResponse.ExpiresIn) * time.Second)
refreshExpires := time.Now().Add(time.Duration(loginResponse.RefreshTokenExpiresIn) * time.Second)
response.SendAccessTokenCookieWithExpiry(c, accessToken, expires)
response.SendRefreshTokenCookieWithExpiry(c, refreshToken, refreshExpires)
// Send all login cookies (access token, refresh token, and session ID)
SendLoginCookies(c, loginResponse, sid)
// Send IDToken to the client
response.RespondWithSuccess(c, response.StatusOK, map[string]interface{}{"id_token": loginResponse.IDToken})
@ -673,3 +666,28 @@ func isPrivateIPv6(ip net.IP) bool {
}
return false
}
// SendLoginCookies sends all necessary cookies for a successful login
// This includes access token, refresh token, and session ID cookies with appropriate security settings
func SendLoginCookies(c *gin.Context, loginResponse *LoginResponse, sessionID string) {
// Format tokens with Bearer prefix
accessToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.AccessToken)
refreshToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.RefreshToken)
// Calculate expiration times
expires := time.Now().Add(time.Duration(loginResponse.ExpiresIn) * time.Second)
refreshExpires := time.Now().Add(time.Duration(loginResponse.RefreshTokenExpiresIn) * time.Second)
// Send access token cookie
response.SendAccessTokenCookieWithExpiry(c, accessToken, expires)
// Send refresh token cookie
response.SendRefreshTokenCookieWithExpiry(c, refreshToken, refreshExpires)
// Send session ID cookie with the same expiration as access token
// Using HTTP-only flag for security
options := response.NewSecureCookieOptions().
WithExpires(expires).
WithSameSite("Strict")
response.SendSecureCookieWithOptions(c, "session_id", sessionID, options)
}

96
openapi/user/TODO.md Normal file
View file

@ -0,0 +1,96 @@
# User Module TODO
## ✅ Implemented (5/80)
### Authentication
- ✅ GET `/user/login` - Get login page configuration
- ✅ POST `/user/login` - User login
### OAuth & Third-Party Integration
- ✅ GET `/user/oauth/:provider/authorize` - Get OAuth authorization URL
- ✅ POST `/user/oauth/:provider/authorize/prepare` - Handle OAuth POST callback (Apple, WeChat)
- ✅ POST `/user/oauth/:provider/callback` - Handle OAuth GET callback (Google, GitHub)
## ❌ TODO (75/80)
### Authentication
- ❌ POST `/user/register` - User registration
- ❌ POST `/user/logout` - User logout
### Profile Management
- ❌ GET `/user/profile` - Get user profile
- ❌ PUT `/user/profile` - Update user profile
### Account Security (13 endpoints)
- ❌ Password management (3 endpoints)
- ❌ Email management (5 endpoints)
- ❌ Mobile management (5 endpoints)
### Multi-Factor Authentication (12 endpoints)
- ❌ TOTP management (7 endpoints)
- ❌ SMS MFA management (5 endpoints)
### OAuth & Third-Party Integration
- ❌ GET `/user/oauth/providers` - Get linked OAuth providers
- ❌ DELETE `/user/oauth/:provider` - Unlink OAuth provider
- ❌ GET `/user/oauth/providers/available` - Get available OAuth providers
- ❌ POST `/user/oauth/:provider/connect` - Connect OAuth provider
### API Keys Management (6 endpoints)
- ❌ CRUD operations and regeneration for API keys
### Credits & Top-up (6 endpoints)
- ❌ Credits info, history, and top-up management
### Subscription Management (2 endpoints)
- ❌ Subscription info and updates
### Usage Statistics (2 endpoints)
- ❌ Usage statistics and history
### Billing & Invoices (2 endpoints)
- ❌ Billing history and invoice list
### Referral & Invitations (4 endpoints)
- ❌ Referral codes, statistics, history, commissions
### Team Management (15 endpoints)
- ❌ Team CRUD (5 endpoints)
- ❌ Member management (5 endpoints)
- ❌ Invitation management (5 endpoints)
### Invitation Response (3 endpoints)
- ❌ Cross-module invitation handling
### User Preferences (3 endpoints)
- ❌ User preference settings
### Privacy Settings (3 endpoints)
- ❌ Privacy settings
### User Management (Admin) (5 endpoints)
- ❌ User CRUD operations
## Progress Summary
- **Completion**: 6.25% (5/80)
- **Core Features**: Authentication and OAuth completed
- **Next Steps**: Recommend implementing basic user management (register, logout, profile) first

View file

@ -2,7 +2,9 @@ package user
import (
"context"
"fmt"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/yaoapp/gou/session"
@ -179,3 +181,28 @@ func LoginByUserID(userid string, ip string) (*LoginResponse, error) {
func generateSessionID() string {
return session.ID()
}
// SendLoginCookies sends all necessary cookies for a successful login
// This includes access token, refresh token, and session ID cookies with appropriate security settings
func SendLoginCookies(c *gin.Context, loginResponse *LoginResponse, sessionID string) {
// Format tokens with Bearer prefix
accessToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.AccessToken)
refreshToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.RefreshToken)
// Calculate expiration times
expires := time.Now().Add(time.Duration(loginResponse.ExpiresIn) * time.Second)
refreshExpires := time.Now().Add(time.Duration(loginResponse.RefreshTokenExpiresIn) * time.Second)
// Send access token cookie
response.SendAccessTokenCookieWithExpiry(c, accessToken, expires)
// Send refresh token cookie
response.SendRefreshTokenCookieWithExpiry(c, refreshToken, refreshExpires)
// Send session ID cookie with the same expiration as access token
// Using HTTP-only flag for security
options := response.NewSecureCookieOptions().
WithExpires(expires).
WithSameSite("Strict")
response.SendSecureCookieWithOptions(c, "session_id", sessionID, options)
}

View file

@ -184,15 +184,8 @@ func authback(c *gin.Context) {
return
}
// Authorize Cookie
accessToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.AccessToken)
refreshToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.RefreshToken)
// Send Cookie
expires := time.Now().Add(time.Duration(loginResponse.ExpiresIn) * time.Second)
refreshExpires := time.Now().Add(time.Duration(loginResponse.RefreshTokenExpiresIn) * time.Second)
response.SendAccessTokenCookieWithExpiry(c, accessToken, expires)
response.SendRefreshTokenCookieWithExpiry(c, refreshToken, refreshExpires)
// Send all login cookies (access token, refresh token, and session ID)
SendLoginCookies(c, loginResponse, sid)
// Send IDToken to the client
response.RespondWithSuccess(c, response.StatusOK, map[string]interface{}{"id_token": loginResponse.IDToken})