Merge pull request #760 from umbraco/feature/logout

Feature/logout
This commit is contained in:
Jacob Overgaard
2023-06-06 09:08:07 +02:00
committed by GitHub
12 changed files with 67 additions and 11 deletions

View File

@@ -11,6 +11,8 @@
"./element-api": "./dist-cms/libs/element-api/index.js",
"./extension-api": "./dist-cms/libs/extension-api/index.js",
"./observable-api": "./dist-cms/libs/observable-api/index.js",
"./auth": "./dist-cms/shared/auth/index.js",
"./context": "./dist-cms/shared/context/index.js",
"./events": "./dist-cms/shared/umb-events/index.js",
"./models": "./dist-cms/shared/models/index.js",
"./repository": "./dist-cms/shared/repository/index.js",

View File

@@ -1,6 +1,6 @@
import { UMB_AUTH, UmbAuthFlow } from '@umbraco-cms/backoffice/auth';
import { UMB_APP, UmbAppContext } from '@umbraco-cms/backoffice/context';
import type { UmbAppErrorElement } from './app-error.element.js';
import { UmbAuthFlow } from './auth/index.js';
import { UMB_APP, UmbAppContext } from './app.context.js';
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { UUIIconRegistryEssential } from '@umbraco-cms/backoffice/external/uui';
import { UmbIconRegistry } from '@umbraco-cms/backoffice/icon';
@@ -81,6 +81,8 @@ export class UmbAppElement extends UmbLitElement {
this.#authFlow = new UmbAuthFlow(this.serverUrl, redirectUrl);
this.provideContext(UMB_AUTH, this.#authFlow);
this.provideContext(UMB_APP, new UmbAppContext({ backofficePath: this.backofficePath, serverUrl: this.serverUrl }));
// Try to initialise the auth flow and get the runtime status

View File

@@ -1 +0,0 @@
export * from './auth-flow.js';

View File

@@ -1,4 +1,3 @@
export * from './app-context-config.interface.js';
export * from './app-error.element.js';
export * from './app.context.js';
export * from './app.element.js';

View File

@@ -1,3 +1,5 @@
import { UMB_AUTH } from '@umbraco-cms/backoffice/auth';
import { UMB_APP } from '@umbraco-cms/backoffice/context';
import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from '../../current-user.store.js';
import type { UmbLoggedInUser } from '../../types.js';
import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui';
@@ -15,6 +17,10 @@ export class UmbCurrentUserModalElement extends UmbLitElement {
private _currentUserStore?: UmbCurrentUserStore;
#auth?: typeof UMB_AUTH.TYPE;
#appContext?: typeof UMB_APP.TYPE;
constructor() {
super();
@@ -23,6 +29,14 @@ export class UmbCurrentUserModalElement extends UmbLitElement {
this._observeCurrentUser();
});
this.consumeContext(UMB_AUTH, (instance) => {
this.#auth = instance;
});
this.consumeContext(UMB_APP, (instance) => {
this.#appContext = instance;
});
this._observeCurrentUser();
}
@@ -38,8 +52,13 @@ export class UmbCurrentUserModalElement extends UmbLitElement {
this.modalContext?.submit();
}
private _logout() {
alert('implement log out');
private async _logout() {
if (!this.#auth) return;
this.#auth.performWithFreshTokens;
await this.#auth.signOut();
let newUrl = this.#appContext ? `${this.#appContext.getBackofficePath()}/login` : '/';
newUrl = newUrl.replace(/\/\//g, '/');
location.href = newUrl;
}
render() {

View File

@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
import type { IUmbAuth } from './auth.interface.js';
import {
BaseTokenRequestHandler,
BasicQueryStringUtils,
@@ -32,6 +33,8 @@ import {
const requestor = new FetchRequestor();
const TOKEN_RESPONSE_NAME = 'umb:userAuthTokenResponse';
/**
* This class is needed to prevent the hash from being parsed as part of the query string.
*/
@@ -78,7 +81,7 @@ class UmbNoHashQueryStringUtils extends BasicQueryStringUtils {
* a. This will redirect the user to the authorization endpoint of the server
* 4. After login, get the latest token before each request to the server by calling the `performWithFreshTokens` method
*/
export class UmbAuthFlow {
export class UmbAuthFlow implements IUmbAuth {
// handlers
readonly #notifier: AuthorizationNotifier;
readonly #authorizationHandler: RedirectRequestHandler;
@@ -155,7 +158,7 @@ export class UmbAuthFlow {
async setInitialState() {
// Ensure there is a connection to the server
await this.fetchServiceConfiguration();
const tokenResponseJson = await this.#storageBackend.getItem('tokenResponse');
const tokenResponseJson = await this.#storageBackend.getItem(TOKEN_RESPONSE_NAME);
if (tokenResponseJson) {
const response = new TokenResponse(JSON.parse(tokenResponseJson));
if (response.isValid()) {
@@ -238,7 +241,7 @@ export class UmbAuthFlow {
// forget all cached token state
this.#accessTokenResponse = undefined;
this.#refreshToken = undefined;
await this.#storageBackend.removeItem('tokenResponse');
await this.#storageBackend.removeItem(TOKEN_RESPONSE_NAME);
}
/**
@@ -282,7 +285,7 @@ export class UmbAuthFlow {
*/
async #saveTokenState() {
if (this.#accessTokenResponse) {
await this.#storageBackend.setItem('tokenResponse', JSON.stringify(this.#accessTokenResponse.toJson()));
await this.#storageBackend.setItem(TOKEN_RESPONSE_NAME, JSON.stringify(this.#accessTokenResponse.toJson()));
}
}

View File

@@ -0,0 +1,17 @@
export interface IUmbAuth {
/**
* Get the current user's access token.
*
* @example
* ```js
* const token = await auth.getAccessToken();
* const result = await fetch('https://my-api.com', { headers: { Authorization: `Bearer ${token}` } });
* ```
*/
performWithFreshTokens(): Promise<string>;
/**
* Sign out the current user.
*/
signOut(): Promise<void>;
}

View File

@@ -0,0 +1,10 @@
import { IUmbAuth } from './auth.interface.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export type { IUmbAuth } from './auth.interface.js';
export { UmbAuthFlow } from './auth-flow.js';
export const UMB_AUTH = new UmbContextToken<IUmbAuth>(
'UmbAuth',
'An instance of UmbAuthFlow that should be shared across the app.'
);

View File

@@ -1,4 +1,4 @@
import { UmbAppContextConfig } from './app-context-config.interface.js';
import { UmbAppContextConfig } from '../../apps/app/app-context-config.interface.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export class UmbAppContext {

View File

@@ -0,0 +1 @@
export * from './app.context.js';

View File

@@ -35,6 +35,8 @@
"@umbraco-cms/backoffice/observable-api": ["src/libs/observable-api"],
// SHARED
"@umbraco-cms/backoffice/auth": ["src/shared/auth"],
"@umbraco-cms/backoffice/context": ["src/shared/context"],
"@umbraco-cms/backoffice/events": ["src/shared/umb-events"],
"@umbraco-cms/backoffice/models": ["src/shared/models"],
"@umbraco-cms/backoffice/repository": ["src/shared/repository"],

View File

@@ -48,6 +48,8 @@ export default {
'@umbraco-cms/backoffice/extension-api': './src/libs/extension-api/index.ts',
'@umbraco-cms/backoffice/observable-api': './src/libs/observable-api/index.ts',
'@umbraco-cms/backoffice/auth': './src/shared/auth/index.ts',
'@umbraco-cms/backoffice/context': './src/shared/context/index.ts',
'@umbraco-cms/backoffice/events': './src/shared/umb-events/index.ts',
'@umbraco-cms/backoffice/models': './src/shared/models/index.ts',
'@umbraco-cms/backoffice/repository': './src/shared/repository/index.ts',