From 4c17724f0095ee721d9b9ac71cc71439f31ceed9 Mon Sep 17 00:00:00 2001 From: daveoconnor Date: Fri, 4 Oct 2024 10:09:44 -0700 Subject: [PATCH] Updated login flow to match Figma (#1167, #1128) (#1311) Includes email for various signup/login related events which we'll need to ensure there's support for in staging and prod --- config/settings.py | 4 +- config/urls.py | 6 ++ docs/development_setup_notes.md | 20 ++++++ requirements.in | 3 +- requirements.txt | 6 +- templates/account/email_confirm.html | 37 +++++++++++ templates/account/signup.html | 8 +-- templates/account/verification_sent.html | 14 ++++ .../socialaccount/snippets/provider_list.html | 65 +++++++++---------- users/views.py | 12 +++- 10 files changed, 130 insertions(+), 45 deletions(-) create mode 100644 templates/account/email_confirm.html create mode 100644 templates/account/verification_sent.html diff --git a/config/settings.py b/config/settings.py index e3d6533f..8a44d5da 100755 --- a/config/settings.py +++ b/config/settings.py @@ -110,6 +110,7 @@ MIDDLEWARE = [ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + "allauth.account.middleware.AccountMiddleware", "oauth2_provider.middleware.OAuth2TokenMiddleware", ] @@ -313,7 +314,7 @@ JDOODLE_API_CLIENT_SECRET = env("JDOODLE_API_CLIENT_SECRET", "") # Django Allauth settings -ACCOUNT_EMAIL_VERIFICATION = "none" +ACCOUNT_EMAIL_VERIFICATION = "mandatory" LOGIN_REDIRECT_URL = "home" ACCOUNT_LOGOUT_ON_GET = True ACCOUNT_USER_MODEL_USERNAME_FIELD = None @@ -343,6 +344,7 @@ SOCIALACCOUNT_PROVIDERS = { "AUTH_PARAMS": { "access_type": "online", }, + "OAUTH_PKCE_ENABLED": True, } } diff --git a/config/urls.py b/config/urls.py index 27f63161..fdd4111e 100755 --- a/config/urls.py +++ b/config/urls.py @@ -60,6 +60,7 @@ from news.views import ( from users.views import ( CurrentUserAPIView, CurrentUserProfileView, + CustomEmailVerificationSentView, CustomLoginView, CustomSignupView, CustomSocialSignupViewView, @@ -95,6 +96,11 @@ urlpatterns = ( ), path("accounts/signup/", CustomSignupView.as_view(), name="account_signup"), path("accounts/login/", CustomLoginView.as_view(), name="account_login"), + path( + "accounts/confirm-email/", + CustomEmailVerificationSentView.as_view(), + name="account_confirm_email", + ), path("accounts/", include("allauth.urls")), path("users/me/", CurrentUserProfileView.as_view(), name="profile-account"), path("users//", ProfileView.as_view(), name="profile-user"), diff --git a/docs/development_setup_notes.md b/docs/development_setup_notes.md index 782ef4a2..8585fd60 100644 --- a/docs/development_setup_notes.md +++ b/docs/development_setup_notes.md @@ -286,6 +286,7 @@ Follow these instructions to use the social logins through django-allauth on you See https://testdriven.io/blog/django-social-auth/ for more information. +#### Github - Go to https://github.com/settings/applications/new and add a new OAuth application - Set `http://localhost:8000` as the Homepage URL - Set `http://localhost:8000/accounts/github/login/callback/` as the Callback URL @@ -314,3 +315,22 @@ It's ready! To test the flow including authorizing Github for the Boost account, log into your GitHub account settings and click **Applications** in the left menu. Find the "Boost" authorization and delete it. The next time you log into Boost with this GitHub account, you will have to re-authorize it. The 'Authorized OAuth Apps' tab in your GitHub Applications + +#### Google + +More detailed instructions at: + +https://docs.allauth.org/en/latest/socialaccount/providers/google.html + +Go to https://console.developers.google.com/ and create a new project. Create OAuth 2.0 credentials. + +The client id is the full value including domain and tld. + +For the "authorized javascript origins" values use: + +* `http://localhost:8000` + +For the "authorized redirect URIs" use: + +* `http://localhost:8000/accounts/google/login/callback/` +* `http://localhost:8000/accounts/google/login/callback/?flowName=GeneralOAuthFlow` diff --git a/requirements.in b/requirements.in index ead5945a..dccb252c 100644 --- a/requirements.in +++ b/requirements.in @@ -1,7 +1,8 @@ Django>=4.0, <5.0 bumpversion django-admin-env-notice -django-allauth==0.53.1 +django-allauth +django-allauth[socialaccount] django-anymail[mailgun] django-cors-headers django-db-geventpool diff --git a/requirements.txt b/requirements.txt index 987ebcc0..69e63d51 100644 --- a/requirements.txt +++ b/requirements.txt @@ -70,8 +70,6 @@ cryptography==43.0.0 # pyjwt decorator==5.1.1 # via ipython -defusedxml==0.7.1 - # via python3-openid distlib==0.3.8 # via virtualenv dj-database-url==2.2.0 @@ -99,7 +97,7 @@ django==4.2.15 # model-bakery django-admin-env-notice==1.0 # via -r ./requirements.in -django-allauth==0.53.1 +django-allauth[socialaccount]==65.0.2 # via -r ./requirements.in django-anymail[mailgun]==11.1 # via -r ./requirements.in @@ -281,8 +279,6 @@ python-frontmatter==1.1.0 # via -r ./requirements.in python-json-logger==2.0.7 # via -r ./requirements.in -python3-openid==3.2.0 - # via django-allauth pytz==2024.1 # via django-oauth-toolkit pyyaml==6.0.2 diff --git a/templates/account/email_confirm.html b/templates/account/email_confirm.html new file mode 100644 index 00000000..e71c8208 --- /dev/null +++ b/templates/account/email_confirm.html @@ -0,0 +1,37 @@ +{% extends "base.html" %} +{% load i18n %} +{% load account %} + +{% block content %} +
+
+
+ {% if confirmation %} + {% user_display confirmation.email_address.user as user_display %} + {% if can_confirm %} +

+ {% blocktrans with confirmation.email_address.email as email %}Please confirm that {{ email }} is an email address that you used to sign up for an account.{% endblocktrans %} +

+ {% url 'account_confirm_email' confirmation.key as action_url %} +
+ {% csrf_token %} + {{ redirect_field }} + +
+ {% else %} +

+ {% blocktrans %}Unable to confirm {{ email }} because it is already confirmed by a different account.{% endblocktrans %} +

+ {% endif %} + {% else %} + {% url 'account_email' as email_url %} +

+ {% blocktrans %}This email confirmation link expired or is invalid. Please issue a new email confirmation request.{% endblocktrans %} +

+ {% endif %} +
+
+
+{% endblock %} diff --git a/templates/account/signup.html b/templates/account/signup.html index a93c40cc..aa346048 100755 --- a/templates/account/signup.html +++ b/templates/account/signup.html @@ -146,8 +146,8 @@ diff --git a/templates/account/verification_sent.html b/templates/account/verification_sent.html new file mode 100644 index 00000000..5edd323d --- /dev/null +++ b/templates/account/verification_sent.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% load account socialaccount i18n %} + +{% block content %} +
+
+
+

An email has been sent to the provided email address

+

Please click on the link in the email to finish the sign up process. The link will expire in {{ EMAIL_CONFIRMATION_EXPIRE_DAYS }} days.

+

Continue to log in

+
+
+
+{% endblock %} diff --git a/templates/socialaccount/snippets/provider_list.html b/templates/socialaccount/snippets/provider_list.html index c3dba705..57bab144 100644 --- a/templates/socialaccount/snippets/provider_list.html +++ b/templates/socialaccount/snippets/provider_list.html @@ -1,36 +1,35 @@ {% load socialaccount %} {% get_providers as socialaccount_providers %} - -{% for provider in socialaccount_providers %} -{% if provider.id == "openid" %} -{% for brand in provider.get_brands %} - {{brand.name}} -{% endfor %} -{% endif %} - {% if provider.name == "GitHub" %} - - Last Log in - - Use {{provider.name}} - - {% endif %} - {% if provider.name == "Google" %} - - Last Log in - - Use {{provider.name}} - - {% endif %} -{% endfor %} + {% for provider in socialaccount_providers %} + {% if provider.id == "openid" %} + {% for brand in provider.get_brands %} + {{brand.name}} + {% endfor %} + {% endif %} + {% if provider.name == "GitHub" %} + + Last Log in + + Use {{provider.name}} + + {% endif %} + {% if provider.name == "Google" %} + + Last Log in + + Use {{provider.name}} + + {% endif %} + {% endfor %} diff --git a/users/views.py b/users/views.py index b1c2c2bc..5083bb62 100644 --- a/users/views.py +++ b/users/views.py @@ -1,3 +1,4 @@ +from allauth.account import app_settings from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.messages.views import SuccessMessageMixin @@ -7,7 +8,7 @@ from django.views.generic import DetailView from django.views.generic.base import TemplateView from allauth.account.forms import ChangePasswordForm, ResetPasswordForm -from allauth.account.views import LoginView, SignupView +from allauth.account.views import LoginView, SignupView, EmailVerificationSentView from allauth.socialaccount.models import SocialAccount from allauth.socialaccount.views import SignupView as SocialSignupView @@ -269,3 +270,12 @@ class CustomLoginView(LoginView): "contributor_account_redirect_message", None ) return context + + +class CustomEmailVerificationSentView(EmailVerificationSentView): + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context[ + "EMAIL_CONFIRMATION_EXPIRE_DAYS" + ] = app_settings.EMAIL_CONFIRMATION_EXPIRE_DAYS + return context