mirror of
https://github.com/discourse/discourse.git
synced 2025-06-07 14:36:01 +08:00
FIX: Automatic auth flow with full page login/signup (#30928)
Co-authored-by: Penar Musaraj <pmusaraj@gmail.com>
This commit is contained in:
@ -140,7 +140,11 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (siteSettings.full_page_login) {
|
if (siteSettings.full_page_login) {
|
||||||
router.transitionTo("signup").then((signup) => {
|
router
|
||||||
|
.transitionTo("signup", {
|
||||||
|
queryParams: { authComplete: true },
|
||||||
|
})
|
||||||
|
.then((signup) => {
|
||||||
const signupController =
|
const signupController =
|
||||||
signup.controller || owner.lookup("controller:signup");
|
signup.controller || owner.lookup("controller:signup");
|
||||||
Object.keys(createAccountProps || {}).forEach((key) => {
|
Object.keys(createAccountProps || {}).forEach((key) => {
|
||||||
|
@ -17,7 +17,6 @@ import DiscourseURL from "discourse/lib/url";
|
|||||||
import { postRNWebviewMessage } from "discourse/lib/utilities";
|
import { postRNWebviewMessage } from "discourse/lib/utilities";
|
||||||
import Category from "discourse/models/category";
|
import Category from "discourse/models/category";
|
||||||
import Composer from "discourse/models/composer";
|
import Composer from "discourse/models/composer";
|
||||||
import { findAll } from "discourse/models/login-method";
|
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
import { i18n } from "discourse-i18n";
|
import { i18n } from "discourse-i18n";
|
||||||
|
|
||||||
@ -44,17 +43,6 @@ export default class ApplicationRoute extends DiscourseRoute {
|
|||||||
@setting("title") siteTitle;
|
@setting("title") siteTitle;
|
||||||
@setting("short_site_description") shortSiteDescription;
|
@setting("short_site_description") shortSiteDescription;
|
||||||
|
|
||||||
get isOnlyOneExternalLoginMethod() {
|
|
||||||
return (
|
|
||||||
!this.siteSettings.enable_local_logins &&
|
|
||||||
this.externalLoginMethods.length === 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get externalLoginMethods() {
|
|
||||||
return findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
loading(transition) {
|
loading(transition) {
|
||||||
this.loadingSlider.transitionStarted();
|
this.loadingSlider.transitionStarted();
|
||||||
@ -295,8 +283,8 @@ export default class ApplicationRoute extends DiscourseRoute {
|
|||||||
: encodeURIComponent(window.location.pathname);
|
: encodeURIComponent(window.location.pathname);
|
||||||
window.location = getURL("/session/sso?return_path=" + returnPath);
|
window.location = getURL("/session/sso?return_path=" + returnPath);
|
||||||
} else {
|
} else {
|
||||||
if (this.isOnlyOneExternalLoginMethod) {
|
if (this.login.isOnlyOneExternalLoginMethod) {
|
||||||
this.login.externalLogin(this.externalLoginMethods[0]);
|
this.login.singleExternalLogin();
|
||||||
} else if (this.siteSettings.full_page_login) {
|
} else if (this.siteSettings.full_page_login) {
|
||||||
this.router.transitionTo("login").then((login) => {
|
this.router.transitionTo("login").then((login) => {
|
||||||
login.controller.set("canSignUp", this.controller.canSignUp);
|
login.controller.set("canSignUp", this.controller.canSignUp);
|
||||||
@ -321,11 +309,9 @@ export default class ApplicationRoute extends DiscourseRoute {
|
|||||||
const returnPath = encodeURIComponent(window.location.pathname);
|
const returnPath = encodeURIComponent(window.location.pathname);
|
||||||
window.location = getURL("/session/sso?return_path=" + returnPath);
|
window.location = getURL("/session/sso?return_path=" + returnPath);
|
||||||
} else {
|
} else {
|
||||||
if (this.isOnlyOneExternalLoginMethod) {
|
if (this.login.isOnlyOneExternalLoginMethod) {
|
||||||
// we will automatically redirect to the external auth service
|
// we will automatically redirect to the external auth service
|
||||||
this.login.externalLogin(this.externalLoginMethods[0], {
|
this.login.singleExternalLogin({ signup: true });
|
||||||
signup: true,
|
|
||||||
});
|
|
||||||
} else if (this.siteSettings.full_page_login) {
|
} else if (this.siteSettings.full_page_login) {
|
||||||
this.router.transitionTo("signup").then((signup) => {
|
this.router.transitionTo("signup").then((signup) => {
|
||||||
Object.keys(createAccountProps || {}).forEach((key) => {
|
Object.keys(createAccountProps || {}).forEach((key) => {
|
||||||
|
@ -7,9 +7,12 @@ import DiscourseRoute from "discourse/routes/discourse";
|
|||||||
export default class LoginRoute extends DiscourseRoute {
|
export default class LoginRoute extends DiscourseRoute {
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
@service router;
|
@service router;
|
||||||
|
@service login;
|
||||||
|
|
||||||
beforeModel() {
|
beforeModel() {
|
||||||
if (
|
if (this.login.isOnlyOneExternalLoginMethod) {
|
||||||
|
this.login.singleExternalLogin();
|
||||||
|
} else if (
|
||||||
!this.siteSettings.login_required &&
|
!this.siteSettings.login_required &&
|
||||||
(!this.siteSettings.full_page_login ||
|
(!this.siteSettings.full_page_login ||
|
||||||
this.siteSettings.enable_discourse_connect)
|
this.siteSettings.enable_discourse_connect)
|
||||||
@ -35,6 +38,10 @@ export default class LoginRoute extends DiscourseRoute {
|
|||||||
controller.set("flashType", "");
|
controller.set("flashType", "");
|
||||||
controller.set("flash", "");
|
controller.set("flash", "");
|
||||||
|
|
||||||
|
if (this.login.isOnlyOneExternalLoginMethod) {
|
||||||
|
controller.set("isRedirecting", true);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.siteSettings.login_required) {
|
if (this.siteSettings.login_required) {
|
||||||
controller.set("showLogin", false);
|
controller.set("showLogin", false);
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,29 @@ import { service } from "@ember/service";
|
|||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
export default class SignupRoute extends DiscourseRoute {
|
export default class SignupRoute extends DiscourseRoute {
|
||||||
@service router;
|
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
|
@service router;
|
||||||
|
@service login;
|
||||||
|
|
||||||
beforeModel() {
|
authComplete = false;
|
||||||
|
|
||||||
|
beforeModel(transition) {
|
||||||
|
this.authComplete = transition.to.queryParams.authComplete || false;
|
||||||
|
|
||||||
|
if (this.login.isOnlyOneExternalLoginMethod && !this.authComplete) {
|
||||||
|
this.login.singleExternalLogin({ signup: true });
|
||||||
|
} else {
|
||||||
this.showCreateAccount();
|
this.showCreateAccount();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupController(controller) {
|
||||||
|
super.setupController(...arguments);
|
||||||
|
|
||||||
|
if (this.login.isOnlyOneExternalLoginMethod && !this.authComplete) {
|
||||||
|
controller.set("isRedirecting", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async showCreateAccount() {
|
async showCreateAccount() {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import Service from "@ember/service";
|
import Service, { service } from "@ember/service";
|
||||||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||||
|
import { findAll } from "discourse/models/login-method";
|
||||||
|
|
||||||
@disableImplicitInjections
|
@disableImplicitInjections
|
||||||
export default class LoginService extends Service {
|
export default class LoginService extends Service {
|
||||||
|
@service siteSettings;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async externalLogin(
|
async externalLogin(
|
||||||
loginMethod,
|
loginMethod,
|
||||||
@ -16,4 +19,20 @@ export default class LoginService extends Service {
|
|||||||
setLoggingIn?.(false);
|
setLoggingIn?.(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async singleExternalLogin(opts) {
|
||||||
|
await this.externalLogin(this.externalLoginMethods[0], opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
get isOnlyOneExternalLoginMethod() {
|
||||||
|
return (
|
||||||
|
!this.siteSettings.enable_local_logins &&
|
||||||
|
this.externalLoginMethods.length === 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get externalLoginMethods() {
|
||||||
|
return findAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
{{hide-application-sidebar}}
|
||||||
|
{{body-class "login-page"}}
|
||||||
|
|
||||||
|
{{#if this.isRedirecting}}
|
||||||
|
{{loading-spinner}}
|
||||||
|
{{else}}
|
||||||
{{#if
|
{{#if
|
||||||
(and
|
(and
|
||||||
this.siteSettings.full_page_login
|
this.siteSettings.full_page_login
|
||||||
@ -5,8 +11,6 @@
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
{{hide-application-header-buttons "search" "login" "signup" "menu"}}
|
{{hide-application-header-buttons "search" "login" "signup" "menu"}}
|
||||||
{{hide-application-sidebar}}
|
|
||||||
{{body-class "login-page"}}
|
|
||||||
<div class="login-fullpage">
|
<div class="login-fullpage">
|
||||||
<FlashMessage @flash={{this.flash}} @type={{this.flashType}} />
|
<FlashMessage @flash={{this.flash}} @type={{this.flashType}} />
|
||||||
|
|
||||||
@ -16,7 +20,9 @@
|
|||||||
{{#if this.hasNoLoginOptions}}
|
{{#if this.hasNoLoginOptions}}
|
||||||
<div class={{if this.site.desktopView "login-left-side"}}>
|
<div class={{if this.site.desktopView "login-left-side"}}>
|
||||||
<div class="login-welcome-header no-login-methods-configured">
|
<div class="login-welcome-header no-login-methods-configured">
|
||||||
<h1 class="login-title">{{i18n "login.no_login_methods.title"}}</h1>
|
<h1 class="login-title">{{i18n
|
||||||
|
"login.no_login_methods.title"
|
||||||
|
}}</h1>
|
||||||
<img />
|
<img />
|
||||||
<p class="login-subheader">
|
<p class="login-subheader">
|
||||||
{{html-safe
|
{{html-safe
|
||||||
@ -174,3 +180,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{/if}}
|
@ -2,6 +2,10 @@
|
|||||||
{{hide-application-header-buttons "search" "login" "signup" "menu"}}
|
{{hide-application-header-buttons "search" "login" "signup" "menu"}}
|
||||||
{{hide-application-sidebar}}
|
{{hide-application-sidebar}}
|
||||||
{{body-class "signup-page"}}
|
{{body-class "signup-page"}}
|
||||||
|
|
||||||
|
{{#if this.isRedirecting}}
|
||||||
|
{{loading-spinner}}
|
||||||
|
{{else}}
|
||||||
<div class="signup-fullpage">
|
<div class="signup-fullpage">
|
||||||
<FlashMessage @flash={{this.flash}} @type={{this.flashType}} />
|
<FlashMessage @flash={{this.flash}} @type={{this.flashType}} />
|
||||||
|
|
||||||
@ -148,7 +152,10 @@
|
|||||||
{{else if
|
{{else if
|
||||||
this.siteSettings.show_signup_form_password_instructions
|
this.siteSettings.show_signup_form_password_instructions
|
||||||
}}
|
}}
|
||||||
<span class="more-info" id="password-validation-more-info">
|
<span
|
||||||
|
class="more-info"
|
||||||
|
id="password-validation-more-info"
|
||||||
|
>
|
||||||
{{this.passwordInstructions}}
|
{{this.passwordInstructions}}
|
||||||
</span>
|
</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@ -285,3 +292,4 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{/if}}
|
@ -232,6 +232,34 @@ shared_examples "social authentication scenarios" do |signup_page_object, login_
|
|||||||
expect(page).to have_css(".header-dropdown-toggle.current-user")
|
expect(page).to have_css(".header-dropdown-toggle.current-user")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when there is only one external login method enabled" do
|
||||||
|
before do
|
||||||
|
SiteSetting.enable_google_oauth2_logins = true
|
||||||
|
SiteSetting.enable_local_logins = false
|
||||||
|
end
|
||||||
|
after { reset_omniauth_config(:google_oauth2) }
|
||||||
|
|
||||||
|
it "automatically redirects to the external auth provider" do
|
||||||
|
mock_google_auth
|
||||||
|
visit("/login")
|
||||||
|
|
||||||
|
expect(signup_form).to be_open
|
||||||
|
expect(signup_form).to have_no_password_input
|
||||||
|
expect(signup_form).to have_valid_username
|
||||||
|
expect(signup_form).to have_valid_email
|
||||||
|
signup_form.click_create_account
|
||||||
|
expect(page).to have_css(".header-dropdown-toggle.current-user")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "automatically redirects to the external auth provider when skipping the signup form" do
|
||||||
|
SiteSetting.auth_skip_create_confirm = true
|
||||||
|
mock_google_auth
|
||||||
|
visit("/login")
|
||||||
|
|
||||||
|
expect(page).to have_css(".header-dropdown-toggle.current-user")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when user exists" do
|
context "when user exists" do
|
||||||
|
Reference in New Issue
Block a user