move responsibility of bypass

This commit is contained in:
Niels Lyngsø
2023-11-09 12:45:29 +01:00
parent 7f2ca5f47b
commit 7ae69e0b1e
3 changed files with 46 additions and 19 deletions

View File

@@ -109,7 +109,7 @@ export class UmbAppElement extends UmbLitElement {
OpenAPI.BASE = this.serverUrl;
const redirectUrl = `${window.location.origin}${this.backofficePath}`;
this.#authContext = new UmbAuthContext(this, this.serverUrl, redirectUrl);
this.#authContext = new UmbAuthContext(this, this.serverUrl, redirectUrl, this.bypassAuth);
this.provideContext(UMB_AUTH_CONTEXT, this.#authContext);
@@ -197,13 +197,9 @@ export class UmbAppElement extends UmbLitElement {
OpenAPI.WITH_CREDENTIALS = true;
}
// TODO: This feels like an od placement, move this into some method regarding starting the application/not install/...
this.#listenForLanguageChange();
if (this.#authContext?.isAuthorized()) {
this.#authContext.isLoggedIn.next(true);
} else {
this.#authContext?.isLoggedIn.next(false);
}
}
#redirect() {
@@ -244,8 +240,7 @@ export class UmbAppElement extends UmbLitElement {
}
#isAuthorized(): boolean {
if (!this.#authContext) return false;
return this.bypassAuth ? true : this.#authContext.isAuthorized();
return this.#authContext?.isAuthorized() ?? false;
}
#isAuthorizedGuard(): Guard {

View File

@@ -24,12 +24,13 @@ import {
AuthorizationServiceConfiguration,
GRANT_TYPE_AUTHORIZATION_CODE,
GRANT_TYPE_REFRESH_TOKEN,
RevokeTokenRequest,
//RevokeTokenRequest,
TokenRequest,
TokenResponse,
LocationLike,
StringMap,
} from '@umbraco-cms/backoffice/external/openid';
import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
const requestor = new FetchRequestor();
@@ -82,6 +83,7 @@ class UmbNoHashQueryStringUtils extends BasicQueryStringUtils {
* 4. After login, get the latest token before each request to the server by calling the `performWithFreshTokens` method
*/
export class UmbAuthFlow {
// handlers
readonly #notifier: AuthorizationNotifier;
readonly #authorizationHandler: RedirectRequestHandler;
@@ -98,6 +100,9 @@ export class UmbAuthFlow {
#refreshToken: string | undefined;
#accessTokenResponse: TokenResponse | undefined;
readonly #authorized = new UmbBooleanState<boolean>(false);
readonly authorized = this.#authorized.asObservable();
constructor(
openIdConnectUrl: string,
redirectUri: string,
@@ -142,7 +147,6 @@ export class UmbAuthFlow {
await this.#makeRefreshTokenRequest(response.code, codeVerifier);
await this.performWithFreshTokens();
await this.#saveTokenState();
}
});
}
@@ -167,6 +171,7 @@ export class UmbAuthFlow {
if (response.isValid()) {
this.#accessTokenResponse = response;
this.#refreshToken = this.#accessTokenResponse.refreshToken;
this.checkAuthorization();
}
}
@@ -214,7 +219,7 @@ export class UmbAuthFlow {
}
/**
* This method will check if the user is logged in by validating the timestamp of the stored token.
* Checks if the user is logged in by validating the timestamp of the stored token.
* If no token is stored, it will return false.
*
* @returns true if the user is logged in, false otherwise.
@@ -223,6 +228,17 @@ export class UmbAuthFlow {
return !!this.#accessTokenResponse && this.#accessTokenResponse.isValid();
}
/**
* Checks if the user is logged in by validating the token, this will update authorized state as well.
*
* @returns true if the user is logged in, false otherwise.
*/
checkAuthorization() {
const authorized = this.isAuthorized();
this.#authorized.next(authorized);
return authorized;
}
/**
* This method will sign the user out of the application.
*/
@@ -241,6 +257,7 @@ export class UmbAuthFlow {
// await this.#tokenHandler.performRevokeTokenRequest(this.#configuration, tokenRevokeRequest);
this.#accessTokenResponse = undefined;
this.checkAuthorization();
}
if (this.#refreshToken) {
@@ -285,6 +302,8 @@ export class UmbAuthFlow {
const response = await this.#tokenHandler.performTokenRequest(this.#configuration, request);
this.#accessTokenResponse = response;
await this.#saveTokenState();
this.checkAuthorization();
return response.accessToken;
}
@@ -320,5 +339,6 @@ export class UmbAuthFlow {
const response = await this.#tokenHandler.performTokenRequest(this.#configuration, request);
this.#refreshToken = response.refreshToken;
this.#accessTokenResponse = response;
this.checkAuthorization();
}
}

View File

@@ -12,14 +12,26 @@ export class UmbAuthContext extends UmbBaseController implements IUmbAuth {
#currentUser = new UmbObjectState<UmbLoggedInUser | undefined>(undefined);
readonly currentUser = this.#currentUser.asObservable();
readonly isLoggedIn = new UmbBooleanState<boolean>(false);
#isLoggedIn = new UmbBooleanState<boolean>(false);
readonly isLoggedIn = this.#isLoggedIn.asObservable();
readonly languageIsoCode = this.#currentUser.asObservablePart((user) => user?.languageIsoCode ?? 'en-us');
#authFlow;
constructor(host: UmbControllerHostElement, serverUrl: string, redirectUrl: string) {
constructor(host: UmbControllerHostElement, serverUrl: string, redirectUrl: string, bypassAuth: boolean) {
super(host)
this.#authFlow = new UmbAuthFlow(serverUrl, redirectUrl);
if(bypassAuth) {
this.#isLoggedIn.next(true);
} else {
this.#authFlow = new UmbAuthFlow(serverUrl, redirectUrl);
this.observe(this.#authFlow.authorized, (isAuthorized) => {
if (isAuthorized) {
this.#isLoggedIn.next(true);
} else {
this.#isLoggedIn.next(false);
}
});
}
this.observe(this.isLoggedIn, (isLoggedIn) => {
if (isLoggedIn) {
@@ -32,15 +44,15 @@ export class UmbAuthContext extends UmbBaseController implements IUmbAuth {
* Initiates the login flow.
*/
login(): void {
return this.#authFlow.makeAuthorizationRequest();
return this.#authFlow?.makeAuthorizationRequest();
}
isAuthorized() {
return this.#authFlow.isAuthorized();
return this.#authFlow?.isAuthorized() ?? true;
}
setInitialState(): Promise<void> {
return this.#authFlow.setInitialState();
return this.#authFlow?.setInitialState() ?? Promise.resolve();
}
async fetchCurrentUser(): Promise<UmbLoggedInUser | undefined> {
@@ -60,14 +72,14 @@ export class UmbAuthContext extends UmbBaseController implements IUmbAuth {
* @returns The latest token from the Management API
*/
getLatestToken(): Promise<string> {
return this.#authFlow.performWithFreshTokens();
return this.#authFlow?.performWithFreshTokens() ?? Promise.resolve('bypass');
}
/**
* Signs the user out by removing any tokens from the browser.
*/
signOut(): Promise<void> {
return this.#authFlow.signOut();
return this.#authFlow?.signOut() ?? Promise.resolve();
}
/**