69 lines
5.5 KiB
Markdown
69 lines
5.5 KiB
Markdown
# 05. 계정과 로그인
|
|
|
|
## 1. 두 가지 방식
|
|
| | 게스트 | 디스코드 로그인 |
|
|
|---|---|---|
|
|
| 시작 | 닉네임 한 칸 입력 → "시작하기" | "디스코드로 로그인" → 디스코드 승인 → 돌아옴 |
|
|
| 닉네임 | 입력한 값 | 처음엔 디스코드 표시 이름(global_name, 없으면 username). 계정 페이지에서 언제든 변경 |
|
|
| 프로필 사진 | 닉네임 첫 글자 + 자동 색상 동그라미 | 디스코드 아바타(끌 수 있음) |
|
|
| 유지 | 이 브라우저 쿠키(1년). 쿠키를 지우면 사라짐 | 어느 기기에서든 로그인하면 같은 계정 |
|
|
| 전적 | 이 브라우저에만 | 계정에 저장 |
|
|
| 전환 | 게스트로 쓰다가 "디스코드 연결"하면 전적·닉네임을 디스코드 계정으로 합침 | — |
|
|
|
|
어디서든 로그인이 필요해지면(예: 링크로 방에 들어옴) 같은 화면에서 두 방식을 나란히 보여 주고, 게스트 쪽을 기본으로 강조한다(가장 빠름).
|
|
|
|
## 2. 닉네임 규칙
|
|
- 2~12자, 한글/영문/숫자/공백(앞뒤 공백 제거, 연속 공백 1개로), 이모지·특수문자 불가(`_`, `-`, `.`만 허용).
|
|
- 중복 허용(사람 구분은 내부 ID로). 같은 방에 같은 닉네임이 있으면 화면에서 뒤에 `(2)`를 붙여 구분.
|
|
- 욕설 필터 통과 필수. 실패 시 "다른 닉네임을 써 주세요".
|
|
- 변경은 언제나 가능, 단 게임 진행 중에는 그 게임이 끝난 뒤 반영(진행 중 이름이 바뀌면 혼란). 하루 변경 횟수 제한 10회.
|
|
- 처음 들어오면 닉네임 칸에 무작위 추천 이름(예: "용감한 호랑이")을 미리 채워 두어 그냥 눌러도 시작되게 한다.
|
|
|
|
## 3. 디스코드 OAuth2 흐름
|
|
- 디스코드 개발자 포털에서 앱 생성 → `client_id`, `client_secret`, Redirect URI `https://<도메인>/api/auth/discord/callback` 등록(사용자 작업).
|
|
- 범위(scope): `identify`만(이메일·서버 목록 안 받음).
|
|
- 흐름(Authorization Code + state, 서버가 client secret을 보관하는 기밀 클라이언트):
|
|
1. `GET /api/auth/discord/start?next=/r/123456` → 서버가 `state`(32바이트 무작위)를 만들어 `next`와 함께 짧은 수명(10분) 서명 쿠키에 넣고 디스코드 승인 페이지로 리다이렉트.
|
|
2. 디스코드가 `/api/auth/discord/callback?code&state`로 돌려보냄 → state 비교 → 토큰 교환 → `GET /users/@me`.
|
|
3. `oauth_accounts(provider='discord', provider_user_id)`로 사용자 찾기/만들기. 현재 게스트 세션이 있으면 그 게스트를 이 계정에 **합침**(아래 4절).
|
|
4. 새 세션 발급 → `next`로 리다이렉트(`next`는 우리 사이트 내부 경로만 허용 — 오픈 리다이렉트 방지).
|
|
- 디스코드 액세스 토큰은 사용자 정보를 받은 뒤 저장하지 않는다(필요 없음).
|
|
- 아바타 URL: `https://cdn.discordapp.com/avatars/<id>/<avatar>.png?size=128` (로그인할 때마다 갱신).
|
|
|
|
## 4. 게스트 → 디스코드 합치기
|
|
- 게스트 사용자 G로 로그인된 상태에서 디스코드 계정 D로 로그인하면:
|
|
- D가 처음이면: G에 디스코드 연결을 추가하고 G를 일반 계정으로 바꾼다(닉네임 유지).
|
|
- D가 이미 있으면: G의 전적을 D로 옮기고 G를 삭제. 닉네임은 D 것을 유지. 진행 중인 방의 자리도 D로 바꾼다.
|
|
- 합치기 결과를 토스트로 알림: "디스코드 계정과 연결했어요. 기록이 합쳐졌어요."
|
|
|
|
## 5. 세션
|
|
- 로그인/게스트 생성 시 32바이트 무작위 토큰을 만들어 쿠키 `sid`로 주고, DB에는 SHA-256 해시를 저장.
|
|
- 수명: 게스트 365일, 디스코드 90일(사용할 때마다 연장, 하루 1번만 DB 갱신).
|
|
- 로그아웃: 세션 삭제 + 쿠키 삭제. 게스트가 로그아웃하면 그 게스트 계정에 다시 들어올 수 없다는 경고를 띄운다.
|
|
- 계정 페이지의 "모든 기기에서 로그아웃"은 그 사용자의 모든 세션 삭제.
|
|
|
|
## 6. HTTP API
|
|
| 메서드 | 경로 | 설명 |
|
|
|---|---|---|
|
|
| POST | `/api/auth/guest` | `{nickname}` → 게스트 생성 + 세션 |
|
|
| GET | `/api/auth/discord/start` | 디스코드 로그인 시작 |
|
|
| GET | `/api/auth/discord/callback` | 디스코드 콜백 |
|
|
| POST | `/api/auth/logout` | 로그아웃 |
|
|
| POST | `/api/auth/logout-all` | 모든 기기 로그아웃 |
|
|
| GET | `/api/me` | 내 정보(id, 닉네임, 종류, 아바타, 설정) |
|
|
| PATCH | `/api/me` | `{nickname?, useDiscordAvatar?, settings?}` |
|
|
| GET | `/api/me/stats` | 게임별 전적 |
|
|
| DELETE | `/api/me` | 계정 삭제(확인 문구 입력 필요). 전적 익명화 |
|
|
|
|
## 7. 계정 페이지(/me)
|
|
- 큰 프로필 사진 + 닉네임 + "닉네임 바꾸기" 버튼(누르면 그 자리에서 편집, 저장/취소).
|
|
- 로그인 방식 표시: "게스트" 또는 "디스코드(이름)". 게스트면 "디스코드 연결하기(기록을 안전하게 보관)" 버튼.
|
|
- 화면 설정: 글자 크기(보통/크게/아주 크게), 다크 모드(자동/밝게/어둡게), 소리 켜기/끄기, 진동 켜기/끄기, 색약 모드.
|
|
- 내 전적: 게임별 판 수/승 수.
|
|
- 로그아웃, 모든 기기 로그아웃, 계정 삭제(맨 아래, 작게).
|
|
|
|
## 8. 권한(역할)
|
|
- 일반 / 어드민 / 슈퍼어드민. 자세한 내용은 `14-admin.md`.
|
|
- `/api/me`는 `role`(`user`·`admin`·`superadmin`)을 함께 돌려주고, 웹은 어드민 이상에게만 계정 페이지에 [관리자 페이지] 버튼을 보여 준다.
|
|
- 이용 제한된 계정은 세션이 모두 지워지고 디스코드로 다시 로그인할 수 없다(`/?login=banned`).
|