Sign-in: custom SignInLive, OIDC-only mode and hide OIDC when not configured, locale divider or/oder
This commit is contained in:
parent
3f73a36076
commit
2cab4b0de4
4 changed files with 145 additions and 8 deletions
|
|
@ -369,4 +369,37 @@
|
|||
left: 0 !important;
|
||||
}
|
||||
|
||||
/* Sign-in: hide SSO button and "or" divider when OIDC is not configured.
|
||||
Use .divider (DaisyUI HorizontalRule) because LiveView does not set id on component root. */
|
||||
[data-oidc-configured="false"] [id*="oidc"] {
|
||||
display: none !important;
|
||||
}
|
||||
[data-oidc-configured="false"] a[href*="oidc"] {
|
||||
display: none !important;
|
||||
}
|
||||
[data-oidc-configured="false"] .divider {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Sign-in: when OIDC-only mode is on, hide password form and "or" divider (show only SSO). */
|
||||
[data-oidc-configured="true"][data-oidc-only="true"] [id*="password"] {
|
||||
display: none !important;
|
||||
}
|
||||
[data-oidc-configured="true"][data-oidc-only="true"] .divider {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Sign-in: show "oder" instead of "or" when locale is German (override is compile-time only).
|
||||
Target div.contents so ::after has a box (span may have display:contents). */
|
||||
[data-locale="de"] .divider div.contents {
|
||||
display: block !important;
|
||||
}
|
||||
[data-locale="de"] .divider div.contents > span {
|
||||
font-size: 0;
|
||||
}
|
||||
[data-locale="de"] .divider div.contents::after {
|
||||
content: "oder";
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* This file is for your main application CSS */
|
||||
|
|
|
|||
|
|
@ -38,12 +38,10 @@ defmodule MvWeb.AuthOverrides do
|
|||
set :image_url, nil
|
||||
end
|
||||
|
||||
# Translate the or in the horizontal rule to German
|
||||
# Translate the "or" in the horizontal rule (between password form and SSO).
|
||||
# Uses auth domain so it respects the current locale (e.g. "oder" in German).
|
||||
override AshAuthentication.Phoenix.Components.HorizontalRule do
|
||||
set :text,
|
||||
Gettext.with_locale(MvWeb.Gettext, "de", fn ->
|
||||
Gettext.gettext(MvWeb.Gettext, "or")
|
||||
end)
|
||||
set :text, dgettext("auth", "or")
|
||||
end
|
||||
|
||||
# Hide AshAuthentication's Flash component since we use flash_group in root layout
|
||||
|
|
|
|||
105
lib/mv_web/live/auth/sign_in_live.ex
Normal file
105
lib/mv_web/live/auth/sign_in_live.ex
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
defmodule MvWeb.SignInLive do
|
||||
@moduledoc """
|
||||
Custom sign-in page with language selector and conditional Single Sign-On button.
|
||||
|
||||
- Renders a language selector (same pattern as LinkOidcAccountLive).
|
||||
- Wraps the default AshAuthentication SignIn component in a container with
|
||||
`data-oidc-configured` so that CSS can hide the SSO button when OIDC is not configured.
|
||||
"""
|
||||
use Phoenix.LiveView
|
||||
use Gettext, backend: MvWeb.Gettext
|
||||
|
||||
alias AshAuthentication.Phoenix.Components
|
||||
alias Mv.Config
|
||||
|
||||
@impl true
|
||||
def mount(_params, session, socket) do
|
||||
overrides =
|
||||
session
|
||||
|> Map.get("overrides", [AshAuthentication.Phoenix.Overrides.Default])
|
||||
|
||||
# Locale from session (set by set_locale plug / LiveUserAuth); default "de"
|
||||
locale = session["locale"] || "de"
|
||||
Gettext.put_locale(MvWeb.Gettext, locale)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(overrides: overrides)
|
||||
|> assign_new(:otp_app, fn -> nil end)
|
||||
|> assign(:path, session["path"] || "/")
|
||||
|> assign(:reset_path, session["reset_path"])
|
||||
|> assign(:register_path, session["register_path"])
|
||||
|> assign(:current_tenant, session["tenant"])
|
||||
|> assign(:resources, session["resources"])
|
||||
|> assign(:context, session["context"] || %{})
|
||||
|> assign(:auth_routes_prefix, session["auth_routes_prefix"])
|
||||
|> assign(:gettext_fn, session["gettext_fn"])
|
||||
|> assign(:live_action, :sign_in)
|
||||
|> assign(:oidc_configured, Config.oidc_configured?())
|
||||
|> assign(:oidc_only, Config.oidc_only?())
|
||||
|> assign(:root_class, "grid h-screen place-items-center bg-base-100")
|
||||
|> assign(:sign_in_id, "sign-in")
|
||||
|> assign(:locale, locale)
|
||||
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_params(_, _uri, socket) do
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div
|
||||
class={@root_class}
|
||||
data-oidc-configured={to_string(@oidc_configured)}
|
||||
data-oidc-only={to_string(@oidc_only)}
|
||||
data-locale={@locale}
|
||||
>
|
||||
<%!-- Language selector: use @locale from socket (set by LiveUserAuth) so selection matches actual locale --%>
|
||||
<nav
|
||||
aria-label={dgettext("auth", "Language selection")}
|
||||
class="absolute top-4 right-4 flex justify-end z-10"
|
||||
>
|
||||
<form method="post" action="/set_locale" class="text-sm">
|
||||
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
|
||||
<select
|
||||
name="locale"
|
||||
onchange="this.form.submit()"
|
||||
class="select select-sm select-bordered bg-base-100"
|
||||
aria-label={dgettext("auth", "Select language")}
|
||||
>
|
||||
<option value="de" selected={@locale == "de"}>Deutsch</option>
|
||||
<option value="en" selected={@locale == "en"}>English</option>
|
||||
</select>
|
||||
</form>
|
||||
</nav>
|
||||
|
||||
<div
|
||||
class={@root_class}
|
||||
data-oidc-configured={to_string(@oidc_configured)}
|
||||
data-oidc-only={to_string(@oidc_only)}
|
||||
data-locale={@locale}
|
||||
>
|
||||
<.live_component
|
||||
module={Components.SignIn}
|
||||
otp_app={@otp_app}
|
||||
live_action={@live_action}
|
||||
path={@path}
|
||||
auth_routes_prefix={@auth_routes_prefix}
|
||||
resources={@resources}
|
||||
reset_path={@reset_path}
|
||||
register_path={@register_path}
|
||||
id={@sign_in_id}
|
||||
overrides={@overrides}
|
||||
current_tenant={@current_tenant}
|
||||
context={@context}
|
||||
gettext_fn={@gettext_fn}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
|
@ -112,7 +112,8 @@ defmodule MvWeb.Router do
|
|||
auth_routes_prefix: "/auth",
|
||||
on_mount: [{MvWeb.LiveUserAuth, :live_no_user}],
|
||||
overrides: [MvWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.DaisyUI],
|
||||
gettext_backend: {MvWeb.Gettext, "auth"}
|
||||
gettext_backend: {MvWeb.Gettext, "auth"},
|
||||
live_view: MvWeb.SignInLive
|
||||
|
||||
# Remove this if you do not want to use the reset password feature
|
||||
reset_route auth_routes_prefix: "/auth",
|
||||
|
|
@ -212,8 +213,8 @@ defmodule MvWeb.Router do
|
|||
end)
|
||||
end
|
||||
|
||||
# Our supported languages for now are german and english, english as fallback language
|
||||
# Our supported languages: German and English; default German.
|
||||
defp supported_locale?(locale), do: locale in ["en", "de"]
|
||||
defp fallback_locale(nil), do: "en"
|
||||
defp fallback_locale(nil), do: Application.get_env(:mv, :default_locale, "de")
|
||||
defp fallback_locale(locale), do: locale
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue