forked from baron/baron-sso
브런치 병합 devfront 에러 수정
This commit is contained in:
@@ -554,7 +554,7 @@ func main() {
|
|||||||
KetoService: ketoService,
|
KetoService: ketoService,
|
||||||
})
|
})
|
||||||
requireAdmin := middleware.RequireRole(middleware.RBACConfig{
|
requireAdmin := middleware.RequireRole(middleware.RBACConfig{
|
||||||
AllowedRoles: []string{domain.RoleSuperAdmin, domain.RoleTenantAdmin},
|
AllowedRoles: []string{domain.RoleSuperAdmin, domain.RoleTenantAdmin, domain.RoleRPAdmin},
|
||||||
AuthHandler: authHandler,
|
AuthHandler: authHandler,
|
||||||
KetoService: ketoService,
|
KetoService: ketoService,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4849,26 +4849,40 @@ func (h *AuthHandler) getKratosIdentity(sessionToken string) (string, map[string
|
|||||||
req.Header.Set("X-Session-Token", sessionToken)
|
req.Header.Set("X-Session-Token", sessionToken)
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", nil, err
|
defer resp.Body.Close()
|
||||||
}
|
if resp.StatusCode == http.StatusOK {
|
||||||
defer resp.Body.Close()
|
var result struct {
|
||||||
if resp.StatusCode >= 300 {
|
Identity struct {
|
||||||
body, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))
|
ID string `json:"id"`
|
||||||
return "", nil, fmt.Errorf("kratos whoami failed status=%d body=%s", resp.StatusCode, string(body))
|
Traits map[string]interface{} `json:"traits"`
|
||||||
|
} `json:"identity"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&result); err == nil {
|
||||||
|
return result.Identity.ID, result.Identity.Traits, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result struct {
|
// 2. Kratos 실패 시 Hydra Introspection 시도 (OIDC Access Token 대응)
|
||||||
Identity struct {
|
if h.Hydra != nil {
|
||||||
ID string `json:"id"`
|
slog.Debug("[Auth] Kratos whoami failed, trying Hydra introspection", "token_prefix", sessionToken[:min(len(sessionToken), 10)])
|
||||||
Traits map[string]interface{} `json:"traits"`
|
introspection, err := h.Hydra.IntrospectToken(context.Background(), sessionToken)
|
||||||
} `json:"identity"`
|
if err == nil && introspection["active"] == true {
|
||||||
}
|
subject, _ := introspection["sub"].(string)
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
if subject != "" {
|
||||||
return "", nil, err
|
// Hydra는 Traits를 직접 주지 않으므로, Kratos Admin API로 상세 정보를 가져옴
|
||||||
|
identity, err := h.KratosAdmin.GetIdentity(context.Background(), subject)
|
||||||
|
if err == nil && identity != nil {
|
||||||
|
return identity.ID, identity.Traits, nil
|
||||||
|
}
|
||||||
|
// Identity 정보가 없더라도 최소한 Subject는 반환
|
||||||
|
return subject, map[string]interface{}{}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.Identity.ID, result.Identity.Traits, nil
|
return "", nil, fmt.Errorf("invalid session or token")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AuthHandler) getKratosSessionID(sessionToken string) (string, error) {
|
func (h *AuthHandler) getKratosSessionID(sessionToken string) (string, error) {
|
||||||
|
|||||||
@@ -597,3 +597,34 @@ func (s *HydraAdminService) AcceptLoginRequest(ctx context.Context, challenge st
|
|||||||
|
|
||||||
return &AcceptLoginRequestResponse{RedirectTo: hydraResp.RedirectTo}, nil
|
return &AcceptLoginRequestResponse{RedirectTo: hydraResp.RedirectTo}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *HydraAdminService) IntrospectToken(ctx context.Context, token string) (map[string]interface{}, error) {
|
||||||
|
endpoint := fmt.Sprintf("%s/admin/oauth2/introspect", strings.TrimRight(s.AdminURL, "/"))
|
||||||
|
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("token", token)
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, strings.NewReader(data.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
|
resp, err := s.HttpClient().Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode >= 300 {
|
||||||
|
body, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))
|
||||||
|
return nil, fmt.Errorf("hydra admin: introspect failed status=%d body=%s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,9 +28,11 @@ apiClient.interceptors.response.use(
|
|||||||
(response) => response,
|
(response) => response,
|
||||||
(error) => {
|
(error) => {
|
||||||
if (error.response?.status === 401) {
|
if (error.response?.status === 401) {
|
||||||
// 401 발생 시 로그인 페이지로 리다이렉트하거나 토큰 갱신 로직 필요
|
// 401 발생 시 로그인 페이지로 리다이렉트
|
||||||
// 여기서는 간단히 리다이렉트 처리 (userManager 사용)
|
const isAuthPath = window.location.pathname.startsWith("/callback");
|
||||||
userManager.signinRedirect();
|
if (!isAuthPath) {
|
||||||
|
userManager.signinRedirect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { UserManager, WebStorageStateStore } from "oidc-client-ts";
|
|||||||
import type { AuthProviderProps } from "react-oidc-context";
|
import type { AuthProviderProps } from "react-oidc-context";
|
||||||
|
|
||||||
export const oidcConfig: AuthProviderProps = {
|
export const oidcConfig: AuthProviderProps = {
|
||||||
authority: import.meta.env.VITE_OIDC_AUTHORITY || "http://localhost:3000/api/v1/auth/oidc", // Backend Proxy URL
|
authority: import.meta.env.VITE_OIDC_AUTHORITY || "http://localhost:5000/oidc", // Gateway Proxy URL
|
||||||
client_id: import.meta.env.VITE_OIDC_CLIENT_ID || "devfront-client",
|
client_id: import.meta.env.VITE_OIDC_CLIENT_ID || "devfront-client",
|
||||||
redirect_uri: `${window.location.origin}/callback`,
|
redirect_uri: `${window.location.origin}/callback`,
|
||||||
response_type: "code",
|
response_type: "code",
|
||||||
|
|||||||
Reference in New Issue
Block a user