forked from baron/baron-sso
스코프 동적 처리 작업 문서화
This commit is contained in:
110
docs/consent_scope_selection_flow.md
Normal file
110
docs/consent_scope_selection_flow.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Baron SSO 권한 선택 및 동적 스코프(Scope) 처리 흐름
|
||||
|
||||
이 문서는 사용자가 Consent(권한 동의) 화면에서 특정 권한(Scope)을 선택하고, 그 선택된 권한들이 어떻게 백엔드와 Ory Hydra로 전달되어 처리되는지에 대한 구현 상세를 설명합니다. 또한, 개발자 포털(`devfront`)에서 설정한 권한별 설명이 어떻게 화면에 동적으로 표시되는지 설명합니다.
|
||||
|
||||
## 1. 개요
|
||||
|
||||
사용자 중심의 개인정보 제어를 위해 다음과 같은 기능이 구현되었습니다.
|
||||
|
||||
1. **권한 선택**: 사용자는 필수(Mandatory)가 아닌 권한을 직접 선택하거나 해제할 수 있습니다.
|
||||
2. **동적 설명**: 개발자 포털에서 설정한 각 권한에 대한 사용자 친화적인 설명(한글 등)이 Consent 화면에 표시됩니다.
|
||||
3. **필수 권한 보장**: `openid`와 같이 서비스 동작에 필수적인 권한은 선택 해제가 불가능합니다.
|
||||
|
||||
## 2. 데이터 흐름 (Data Flow)
|
||||
|
||||
### Step 1: Consent 정보 조회 (`GET /consent`)
|
||||
|
||||
사용자가 `/consent` 페이지에 진입하면, 프론트엔드는 백엔드에 상세 정보를 요청합니다.
|
||||
|
||||
1. **Frontend (`userfront`)**: `AuthProxyService.getConsentInfo(challenge)` 호출.
|
||||
2. **Backend (`backend`)**: `AuthHandler.GetConsentRequest` 핸들러 실행.
|
||||
* Hydra Admin API를 호출하여 Consent Request 정보(요청된 스코프, 클라이언트 정보 등)를 가져옵니다.
|
||||
* **핵심 로직**: Hydra Client의 `Metadata` 필드 내 `structured_scopes`를 파싱합니다.
|
||||
* 파싱된 정보를 바탕으로 `scope_details` 객체(설명, 필수 여부 포함)를 생성하여 응답에 추가합니다.
|
||||
|
||||
```json
|
||||
// 백엔드 응답 예시
|
||||
{
|
||||
"challenge": "...",
|
||||
"requested_scope": ["openid", "profile", "email"],
|
||||
"scope_details": {
|
||||
"openid": { "description": "인증 필수 정보", "mandatory": true },
|
||||
"profile": { "description": "프로필 정보", "mandatory": false }
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: UI 렌더링 및 사용자 선택
|
||||
|
||||
1. **Frontend (`userfront`)**: `ConsentScreen` 위젯 렌더링.
|
||||
* 백엔드에서 받은 `requested_scope` 목록을 순회하며 체크박스를 생성합니다.
|
||||
* `scope_details`에 있는 설명을 우선적으로 표시합니다.
|
||||
* `mandatory: true`인 스코프(예: `openid`)는 체크박스를 비활성화(선택 고정)합니다.
|
||||
* 사용자는 나머지 선택 가능한 스코프를 체크하거나 해제합니다.
|
||||
|
||||
### Step 3: 동의 처리 (`POST /consent/accept`)
|
||||
|
||||
사용자가 "동의하고 계속하기" 버튼을 클릭하면, **선택된 스코프 목록만** 백엔드로 전송됩니다.
|
||||
|
||||
1. **Frontend (`userfront`)**: `AuthProxyService.acceptConsent(challenge, grantScope: [...])` 호출.
|
||||
* `grant_scope` 파라미터에 사용자가 최종적으로 선택한 스코프 배열을 담아 보냅니다.
|
||||
|
||||
2. **Backend (`backend`)**: `AuthHandler.AcceptConsentRequest` 핸들러 실행.
|
||||
* 요청 바디에서 `grant_scope`를 추출합니다.
|
||||
* 보안을 위해, 사용자가 보낸 `grant_scope`가 원래 요청된(requested) 스코프에 포함되는지 검증합니다.
|
||||
* 검증된 스코프 목록을 Hydra의 `AcceptConsentRequest` 페이로드(`grant_scope`)에 담아 호출합니다.
|
||||
|
||||
3. **Hydra**:
|
||||
* 전달받은 `grant_scope`만을 포함한 Access Token 및 ID Token을 생성할 준비를 하고, 최종 리다이렉트 URL을 반환합니다.
|
||||
|
||||
## 3. 파일별 구현 상세
|
||||
|
||||
### 1. Backend (`backend/internal/handler/auth_handler.go`)
|
||||
|
||||
* **`GetConsentRequest`**:
|
||||
* Hydra Client의 Metadata(`structured_scopes`)를 읽어 `scope_details`를 응답에 주입하는 로직이 추가되었습니다.
|
||||
* **`AcceptConsentRequest`**:
|
||||
* 요청 바디 구조체에 `GrantScope []string` 필드를 추가했습니다.
|
||||
* Hydra API 호출 시 `RequestedScope` 필드를 사용자가 선택한 스코프로 덮어씌워 전달합니다.
|
||||
|
||||
### 2. Frontend (`userfront/lib/features/auth/presentation/consent_screen.dart`)
|
||||
|
||||
* **`_fetchConsentInfo`**:
|
||||
* API 응답의 `scope_details`를 파싱하여 `_scopeDescriptions`와 `_mandatoryScopes` 상태를 동적으로 업데이트합니다.
|
||||
* **`_acceptConsent`**:
|
||||
* 사용자가 체크한 `_selectedScopes`를 리스트로 변환하여 API 호출 시 전달합니다.
|
||||
* **UI**:
|
||||
* `CheckboxListTile`을 사용하여 각 권한별 선택 UI를 구성했습니다.
|
||||
|
||||
### 3. Frontend Service (`userfront/lib/core/services/auth_proxy_service.dart`)
|
||||
|
||||
* **`acceptConsent`**:
|
||||
* `List<String>? grantScope` 파라미터를 추가하고, API 요청 바디에 포함시키는 기능을 구현했습니다.
|
||||
|
||||
## 4. 메타데이터 구조 (참고)
|
||||
|
||||
개발자 포털(`devfront`)에서 설정된 스코프 메타데이터는 Hydra Client의 `metadata` 필드에 다음과 같이 저장됩니다.
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"structured_scopes": [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "openid",
|
||||
"description": "서비스 이용을 위한 필수 인증 정보입니다.",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "email",
|
||||
"description": "이메일 알림을 받기 위해 필요합니다.",
|
||||
"mandatory": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
백엔드는 이 정보를 읽어서 Consent 화면에 필요한 정보로 가공하여 전달합니다.
|
||||
Reference in New Issue
Block a user