Skip to content

Commit af09dee

Browse files
committed
feat: 병합된 계정으로 로그인을 시도하는 경우, 또는 소셜 로그인이 실패하는 경우 메시지 노출 추가
1 parent 81f769f commit af09dee

6 files changed

Lines changed: 44 additions & 13 deletions

File tree

‎app/core/authn/allauth_adapter.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ def get_frontend_url(self, urlname: str, **kwargs: Any) -> str | None:
9595
if urlname != "socialaccount_login_error":
9696
return super().get_frontend_url(urlname, **kwargs)
9797

98+
if getattr(self.request, "urlconf", None) == "core.account_urls":
99+
self.request.session["login_error"] = "social_login_failed"
100+
return reverse("account-login", urlconf=self.request.urlconf)
101+
98102
allowed = _allowed_frontend_origins()
99103
origin: str | None = None
100104
for header in ("HTTP_X_FRONTEND_DOMAIN", "HTTP_ORIGIN", "HTTP_REFERER"):

‎app/core/const/account.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@
4646
"ko": "병합할 계정 정보를 찾을 수 없습니다. 다시 시도해 주세요.",
4747
"en": "We couldn't find the account to merge. Please try again.",
4848
},
49+
"account_merged": {
50+
"ko": "해당 계정은 다른 계정으로 병합되었습니다. 남기신 계정으로 로그인해 주세요.",
51+
"en": "That account was merged into another. Please sign in with the account you kept.",
52+
},
53+
"social_login_failed": {
54+
"ko": "소셜 로그인에 실패했습니다. 다시 시도해 주세요.",
55+
"en": "Social sign-in failed. Please try again.",
56+
},
4957
}
5058
EMAIL_MESSAGES = {
5159
"verification_sent": {

‎app/user/account_views/account.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def account_home(request: HttpRequest) -> HttpResponse:
2727
def account_login(request: HttpRequest) -> HttpResponse:
2828
target = login_target(request)
2929
redirect_if_authenticated(request, target)
30+
code = request.session.pop("login_error", None)
3031
return render(
3132
request,
3233
"user/account_login.html",
@@ -35,6 +36,7 @@ def account_login(request: HttpRequest) -> HttpResponse:
3536
"redirect_url": HEADLESS_PROVIDER_REDIRECT_URL,
3637
"callback_url": target,
3738
"process": "login",
39+
"error": MERGE_MESSAGES[code]["en" if is_english() else "ko"] if code in MERGE_MESSAGES else None,
3840
},
3941
)
4042

‎app/user/account_views/utils.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from core.middleware.response_exception import ResponseException
4-
from django.contrib.auth import get_user_model
4+
from django.contrib.auth import SESSION_KEY, get_user_model, logout
55
from django.http import HttpRequest
66
from django.shortcuts import redirect
77
from django.urls import reverse, reverse_lazy
@@ -16,13 +16,23 @@
1616
User = get_user_model()
1717

1818

19+
def _reject_merged(request: HttpRequest) -> None:
20+
uid = request.session.get(SESSION_KEY)
21+
if uid and not request.user.is_authenticated and User.objects.filter(pk=uid, merged_to__isnull=False).exists():
22+
logout(request)
23+
request.session["login_error"] = "account_merged"
24+
raise ResponseException(redirect(reverse("account-login")))
25+
26+
1927
def check_login(request: HttpRequest) -> None:
28+
_reject_merged(request)
2029
if not request.user.is_authenticated:
2130
login_url = f"{reverse('account-login')}?{urlencode({'next': request.get_full_path()})}"
2231
raise ResponseException(redirect(login_url))
2332

2433

2534
def redirect_if_authenticated(request: HttpRequest, target: str) -> None:
35+
_reject_merged(request)
2636
if request.user.is_authenticated:
2737
raise ResponseException(redirect(target))
2838

‎app/user/templates/user/account_login.html‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{% block title %}{% if en %}Sign in · PyCon Korea{% else %}로그인 · PyCon Korea{% endif %}{% endblock %}
33
{% block body %}
44
<h1>{% if en %}Sign in to PyCon Korea{% else %}PyCon Korea 계정 로그인{% endif %}</h1>
5+
{% if error %}<p class="error">{{ error }}</p>{% endif %}
56
<p>{% if en %}Sign in with a social account.{% else %}소셜 계정으로 로그인하세요.{% endif %}</p>
67
{% include "user/_provider_forms.html" %}
78
<p class="or">{% if en %}or{% else %}또는{% endif %}</p>

‎app/user/test/merge_view_test.py‎

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import pytest
22
from allauth.account.models import EmailAddress
3+
from allauth.core.context import request_context
34
from allauth.core.exceptions import ImmediateHttpResponse
45
from allauth.socialaccount.models import SocialAccount, SocialLogin
5-
from core.authn.allauth_adapter import SocialAccountLoggingAdapter
6+
from core.authn.allauth_adapter import PyConKRHeadlessAdapter, SocialAccountLoggingAdapter
67
from core.const.account import MERGE_SOURCE_SESSION_KEY
78
from django.urls import reverse
89
from shop.order.models import Order
@@ -107,22 +108,15 @@ def test_start_lists_provider_forms(client, target_user):
107108
assert b'name="process" value="connect"' in response.content
108109

109110

110-
def test_merged_account_session_is_logged_out(client, source_user, target_user):
111+
def test_merged_account_session_logs_out_and_shows_notice(client, source_user, target_user):
111112
UserMergeHistory.objects.create(source=source_user, target=target_user).merge()
112113
client.force_login(source_user) # 병합된(dead) 계정으로 남은 세션
113114

114-
response = client.get(reverse("account-home"))
115+
response = client.get(reverse("account-home"), follow=True)
115116

116-
assert response.status_code == 302
117-
assert "merged=1" in response["Location"]
117+
assert response.redirect_chain[-1][0] == reverse("account-login")
118118
assert "_auth_user_id" not in client.session
119-
120-
121-
def test_login_shows_merged_notice(client, db):
122-
response = client.get(reverse("account-login") + "?merged=1")
123-
124-
assert response.status_code == 200
125-
assert "병합".encode() in response.content
119+
assert "병합".encode() in response.content # login_error 플래시가 error 로 렌더
126120

127121

128122
# ---- AccountLoginView ---------------------------------------------------------
@@ -341,6 +335,18 @@ def test_pre_social_login_ignores_plain_login(rf, source_user, target_user):
341335
assert MERGE_SOURCE_SESSION_KEY not in request.session
342336

343337

338+
def test_social_login_error_on_accounts_host_routes_to_login(rf):
339+
request = rf.get("/")
340+
request.urlconf = "core.account_urls" # accounts 호스트 = HostUrlconfMiddleware 가 세팅
341+
request.session = {}
342+
343+
with request_context(request):
344+
url = PyConKRHeadlessAdapter().get_frontend_url("socialaccount_login_error")
345+
346+
assert url == reverse("account-login", urlconf="core.account_urls")
347+
assert request.session["login_error"] == "social_login_failed"
348+
349+
344350
# ---- 다국어 (en) --------------------------------------------------------------
345351

346352

0 commit comments

Comments
 (0)