feat: add multi-source breed encyclopedia and two-hour refresh sessions
This commit is contained in:
@@ -37,11 +37,17 @@ func (a *API) Register(r *gin.Engine) {
|
||||
api.POST("/auth/login", a.login)
|
||||
api.POST("/auth/dev", a.devLogin)
|
||||
api.POST("/admin/login", a.adminLogin)
|
||||
api.POST("/auth/refresh", a.refreshToken("user"))
|
||||
api.POST("/admin/refresh", a.refreshToken("admin"))
|
||||
api.POST("/auth/logout", a.revokeRefresh("user"))
|
||||
api.POST("/admin/logout", a.revokeRefresh("admin"))
|
||||
|
||||
user := api.Group("")
|
||||
user.Use(a.requireRole("user"))
|
||||
user.GET("/environment", a.environment)
|
||||
user.GET("/me", a.me)
|
||||
user.GET("/breeds", a.listBreeds)
|
||||
user.GET("/breeds/:id", a.breedDetail)
|
||||
user.GET("/pets", a.listPets)
|
||||
user.POST("/pets", a.createPet)
|
||||
user.GET("/pets/:id", a.getPet)
|
||||
@@ -72,6 +78,10 @@ func (a *API) Register(r *gin.Engine) {
|
||||
|
||||
admin := api.Group("/admin")
|
||||
admin.Use(a.requireRole("admin"))
|
||||
admin.GET("/breeds", a.adminBreeds)
|
||||
admin.POST("/breeds", a.createBreed)
|
||||
admin.PUT("/breeds/:id", a.updateBreed)
|
||||
admin.PUT("/breeds/:id/enabled", a.setBreedEnabled)
|
||||
admin.GET("/stats", a.adminStats)
|
||||
admin.GET("/users", a.adminUsers)
|
||||
admin.GET("/users/:id/pets", a.adminUserPets)
|
||||
@@ -86,18 +96,16 @@ func (a *API) Register(r *gin.Engine) {
|
||||
}
|
||||
|
||||
type claims struct {
|
||||
Role string `json:"role"`
|
||||
Role string `json:"role"`
|
||||
SessionID string `json:"sid,omitempty"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func (a *API) token(id, role string) (string, error) {
|
||||
expire := a.cfg.JWT.ExpireHours
|
||||
if expire <= 0 {
|
||||
expire = 168
|
||||
}
|
||||
func (a *API) token(id, role string) (string, error) { return a.sessionToken(id, role, "") }
|
||||
func (a *API) sessionToken(id, role, sessionID string) (string, error) {
|
||||
now := time.Now()
|
||||
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims{Role: role, RegisteredClaims: jwt.RegisteredClaims{
|
||||
Subject: id, IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(expire) * time.Hour)),
|
||||
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims{Role: role, SessionID: sessionID, RegisteredClaims: jwt.RegisteredClaims{
|
||||
ID: uuid.NewString(), Subject: id, IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(2 * time.Hour)),
|
||||
}})
|
||||
return t.SignedString([]byte(a.cfg.JWT.Secret))
|
||||
}
|
||||
@@ -127,6 +135,20 @@ func (a *API) requireRole(role string) gin.HandlerFunc {
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
// Reject credentials issued with the old seven-day lifetime.
|
||||
if cl.IssuedAt == nil || cl.ExpiresAt == nil || cl.ExpiresAt.Sub(cl.IssuedAt.Time) > 2*time.Hour {
|
||||
fail(c, http.StatusUnauthorized, "登录已过期")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
if cl.SessionID != "" {
|
||||
var count int64
|
||||
if !validID(cl.SessionID) || a.db.Model(&model.RefreshSession{}).Where("id = ? AND actor_id = ? AND role = ? AND revoked = false AND expires_at > ?", cl.SessionID, cl.Subject, role, time.Now()).Count(&count).Error != nil || count != 1 {
|
||||
fail(c, http.StatusUnauthorized, "登录已过期")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
if role == "user" {
|
||||
var user model.User
|
||||
if err := a.db.Select("id", "disabled").First(&user, "id = ?", cl.Subject).Error; err != nil || user.Disabled {
|
||||
|
||||
Reference in New Issue
Block a user