mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Fix(BE-304):add refresh token and adjustment permission
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package controllers
|
||||
|
||||
type refreshTokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Scope string `json:"scope"`
|
||||
IDToken string `json:"id_token"`
|
||||
Error string `json:"error"`
|
||||
Description string `json:"error_description"`
|
||||
}
|
||||
|
||||
@@ -138,6 +138,86 @@ func (h *Controller) Start(c *fiber.Ctx) error {
|
||||
return c.Redirect(authorizeURL.String(), fiber.StatusFound)
|
||||
}
|
||||
|
||||
// Refresh exchanges the current SSO refresh token for a new access/refresh pair
|
||||
// without redirecting the browser to the SSO login page.
|
||||
func (h *Controller) Refresh(c *fiber.Ctx) error {
|
||||
refreshName := resolveSSOCookieName(config.SSORefreshCookieName, "refresh")
|
||||
refreshToken := strings.TrimSpace(c.Cookies(refreshName))
|
||||
if refreshToken == "" {
|
||||
return fiber.NewError(fiber.StatusUnauthorized, "unauthenticated")
|
||||
}
|
||||
|
||||
tokenEndpoint := strings.TrimSpace(config.SSOTokenURL)
|
||||
if tokenEndpoint == "" {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "token endpoint not configured")
|
||||
}
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("grant_type", "refresh_token")
|
||||
form.Set("refresh_token", refreshToken)
|
||||
|
||||
req, err := http.NewRequestWithContext(c.Context(), http.MethodPost, tokenEndpoint, strings.NewReader(form.Encode()))
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to create refresh request")
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
resp, err := h.httpClient.Do(req)
|
||||
if err != nil {
|
||||
utils.Log.Errorf("token refresh request failed: %v", err)
|
||||
return fiber.NewError(fiber.StatusBadGateway, "failed to refresh access token")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
utils.Log.Warnf("token refresh response status %d", resp.StatusCode)
|
||||
return fiber.NewError(fiber.StatusUnauthorized, "unauthenticated")
|
||||
}
|
||||
|
||||
var tokenResp refreshTokenResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadGateway, "invalid token response")
|
||||
}
|
||||
if tokenResp.Error != "" {
|
||||
return fiber.NewError(fiber.StatusBadGateway, tokenResp.Description)
|
||||
}
|
||||
if tokenResp.AccessToken == "" {
|
||||
return fiber.NewError(fiber.StatusBadGateway, "missing access token")
|
||||
}
|
||||
|
||||
verification, err := sso.VerifyAccessToken(tokenResp.AccessToken)
|
||||
if err != nil {
|
||||
utils.Log.Errorf("access token verification failed: %v", err)
|
||||
return fiber.NewError(fiber.StatusUnauthorized, "invalid access token")
|
||||
}
|
||||
|
||||
issueCookies(c, struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Scope string `json:"scope"`
|
||||
IDToken string `json:"id_token"`
|
||||
Error string `json:"error"`
|
||||
Description string `json:"error_description"`
|
||||
}{
|
||||
AccessToken: tokenResp.AccessToken,
|
||||
RefreshToken: tokenResp.RefreshToken,
|
||||
TokenType: tokenResp.TokenType,
|
||||
ExpiresIn: tokenResp.ExpiresIn,
|
||||
Scope: tokenResp.Scope,
|
||||
IDToken: tokenResp.IDToken,
|
||||
Error: tokenResp.Error,
|
||||
Description: tokenResp.Description,
|
||||
}, verification)
|
||||
|
||||
utils.Log.WithFields(logrus.Fields{
|
||||
"user_id": verification.UserID,
|
||||
}).Info("sso refresh successful")
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "ok"})
|
||||
}
|
||||
|
||||
// Callback handles the redirect from SSO containing the authorization code.
|
||||
func (h *Controller) Callback(c *fiber.Ctx) error {
|
||||
state := strings.TrimSpace(c.Query("state"))
|
||||
|
||||
@@ -31,6 +31,7 @@ func Routes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
||||
group.Get("/start", middleware.NewLimiter(30, time.Minute), ctrl.Start)
|
||||
group.Get("/callback", ctrl.Callback)
|
||||
group.Get("/userinfo", middleware.NewLimiter(60, time.Minute), ctrl.UserInfo)
|
||||
group.Post("/refresh", middleware.NewLimiter(60, time.Minute), ctrl.Refresh)
|
||||
group.Post("/logout", middleware.NewLimiter(60, time.Minute), ctrl.Logout)
|
||||
group.Post("/users/sync", middleware.NewLimiter(30, time.Minute), syncCtrl.Sync)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user