Merge pull request #779 from umbraco/feature/current-user
Feature/current-user
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { UmbAppErrorElement } from './app-error.element.js';
|
||||
import { UMB_AUTH, UmbAuthFlow } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_AUTH, UmbAuthFlow, UmbAuthContext } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_APP, UmbAppContext } from '@umbraco-cms/backoffice/context';
|
||||
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UUIIconRegistryEssential } from '@umbraco-cms/backoffice/external/uui';
|
||||
@@ -81,7 +81,9 @@ export class UmbAppElement extends UmbLitElement {
|
||||
|
||||
this.#authFlow = new UmbAuthFlow(this.serverUrl, redirectUrl);
|
||||
|
||||
this.provideContext(UMB_AUTH, this.#authFlow);
|
||||
const authContext = new UmbAuthContext(this, this.#authFlow);
|
||||
|
||||
this.provideContext(UMB_AUTH, authContext);
|
||||
|
||||
this.provideContext(UMB_APP, new UmbAppContext({ backofficePath: this.backofficePath, serverUrl: this.serverUrl }));
|
||||
|
||||
@@ -99,6 +101,8 @@ export class UmbAppElement extends UmbLitElement {
|
||||
OpenAPI.WITH_CREDENTIALS = true;
|
||||
}
|
||||
|
||||
authContext.isLoggedIn.next(true);
|
||||
|
||||
// Initialise the router
|
||||
this.#redirect();
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import { UmbData } from './data.js';
|
||||
import { PagedUserResponseModel, UserResponseModel, UserStateModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
@@ -18,6 +19,25 @@ class UmbUsersData extends UmbData<UserResponseModel> {
|
||||
return this.data.find((user) => user.id === id);
|
||||
}
|
||||
|
||||
getCurrentUser(): UmbLoggedInUser {
|
||||
const firstUser = this.data[0];
|
||||
|
||||
return {
|
||||
$type: 'CurrentUserResponseModel',
|
||||
id: firstUser.id,
|
||||
name: firstUser.name,
|
||||
email: firstUser.email,
|
||||
userName: firstUser.email,
|
||||
avatarUrls: [],
|
||||
hasAccessToAllLanguages: true,
|
||||
languageIsoCode: firstUser.languageIsoCode,
|
||||
languages: [],
|
||||
contentStartNodeIds: firstUser.contentStartNodeIds,
|
||||
mediaStartNodeIds: firstUser.mediaStartNodeIds,
|
||||
permissions: [],
|
||||
};
|
||||
}
|
||||
|
||||
save(id: string, saveItem: UserResponseModel) {
|
||||
const foundIndex = this.data.findIndex((item) => item.id === id);
|
||||
if (foundIndex !== -1) {
|
||||
@@ -96,9 +116,9 @@ export const data: Array<UserResponseModel & { type: string }> = [
|
||||
$type: 'UserResponseModel',
|
||||
contentStartNodeIds: [],
|
||||
mediaStartNodeIds: [],
|
||||
name: 'Erny Baptista',
|
||||
email: 'ebaptista1@csmonitor.com',
|
||||
languageIsoCode: 'Kannada',
|
||||
name: 'Umbraco User',
|
||||
email: 'noreply@umbraco.com',
|
||||
languageIsoCode: 'en-US',
|
||||
state: UserStateModel.ACTIVE,
|
||||
lastLoginDate: '9/10/2022',
|
||||
lastLockoutDate: '11/23/2021',
|
||||
|
||||
@@ -3,18 +3,31 @@ const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../data/users.data.js';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
let isAuthenticated = true;
|
||||
const slug = '/user';
|
||||
|
||||
export const handlers = [
|
||||
rest.get(umbracoPath(`${slug}`), (req, res, ctx) => {
|
||||
rest.get(umbracoPath(`${slug}/filter`), (req, res, ctx) => {
|
||||
//TODO: Implementer filter
|
||||
const response = umbUsersData.getAll();
|
||||
|
||||
return res(ctx.status(200), ctx.json(response));
|
||||
}),
|
||||
|
||||
rest.get(umbracoPath(`${slug}/filter`), (req, res, ctx) => {
|
||||
//TODO: Implementer filter
|
||||
rest.get(umbracoPath(`${slug}/current`), (_req, res, ctx) => {
|
||||
const loggedInUser = umbUsersData.getCurrentUser();
|
||||
return res(ctx.status(200), ctx.json(loggedInUser));
|
||||
}),
|
||||
|
||||
rest.get(umbracoPath(`${slug}/sections`), (_req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
sections: ['Umb.Section.Content', 'Umb.Section.Media', 'Umb.Section.Settings', 'My.Section.Custom'],
|
||||
})
|
||||
);
|
||||
}),
|
||||
|
||||
rest.get(umbracoPath(`${slug}`), (req, res, ctx) => {
|
||||
const response = umbUsersData.getAll();
|
||||
|
||||
return res(ctx.status(200), ctx.json(response));
|
||||
@@ -40,51 +53,4 @@ export const handlers = [
|
||||
|
||||
return res(ctx.status(200), ctx.json(saved));
|
||||
}),
|
||||
rest.post(umbracoPath('/user/login'), (_req, res, ctx) => {
|
||||
// Persist user's authentication in the session
|
||||
isAuthenticated = true;
|
||||
return res(
|
||||
// Respond with a 200 status code
|
||||
ctx.status(201)
|
||||
);
|
||||
}),
|
||||
|
||||
rest.post(umbracoPath('/user/logout'), (_req, res, ctx) => {
|
||||
// Persist user's authentication in the session
|
||||
isAuthenticated = false;
|
||||
return res(
|
||||
// Respond with a 200 status code
|
||||
ctx.status(201)
|
||||
);
|
||||
}),
|
||||
|
||||
rest.get(umbracoPath('/user'), (_req, res, ctx) => {
|
||||
// Check if the user is authenticated in this session
|
||||
if (!isAuthenticated) {
|
||||
// If not authenticated, respond with a 403 error
|
||||
return res(
|
||||
ctx.status(403),
|
||||
ctx.json({
|
||||
errorMessage: 'Not authorized',
|
||||
})
|
||||
);
|
||||
}
|
||||
// If authenticated, return a mocked user details
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
username: 'admin',
|
||||
role: 'administrator',
|
||||
})
|
||||
);
|
||||
}),
|
||||
|
||||
rest.get(umbracoPath('/user/sections'), (_req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
sections: ['Umb.Section.Content', 'Umb.Section.Media', 'Umb.Section.Settings', 'My.Section.Custom'],
|
||||
})
|
||||
);
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -1,12 +1,40 @@
|
||||
import { css, html, LitElement, customElement } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UMB_AUTH } from '@umbraco-cms/backoffice/auth';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
@customElement('umb-umbraco-news-dashboard')
|
||||
export class UmbUmbracoNewsDashboardElement extends LitElement {
|
||||
export class UmbUmbracoNewsDashboardElement extends UmbLitElement {
|
||||
#auth?: typeof UMB_AUTH.TYPE;
|
||||
|
||||
@state()
|
||||
private name = '';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this.#auth = instance;
|
||||
this.#observeCurrentUser();
|
||||
});
|
||||
}
|
||||
|
||||
#observeCurrentUser(): void {
|
||||
if (!this.#auth) return;
|
||||
this.observe(this.#auth.currentUser, (user) => {
|
||||
this.name = user?.name ?? '';
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-box>
|
||||
<h1>Welcome</h1>
|
||||
<p>You can find details about the POC in the readme.md file.</p>
|
||||
<h1>Welcome, ${this.name}</h1>
|
||||
<p>This is a preview version of Umbraco, where you can have a first-hand look at the new Backoffice.</p>
|
||||
<p>There is currently very limited functionality.</p>
|
||||
<p>
|
||||
Please refer to the
|
||||
<a target="_blank" href="http://docs.umbraco.com/umbraco-backoffice/">documentation</a> to learn more about
|
||||
what is possible.
|
||||
</p>
|
||||
</uui-box>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { UmbLoggedInUser } from './types.js';
|
||||
import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from './current-user.store.js';
|
||||
import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { css, CSSResultGroup, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import {
|
||||
@@ -8,13 +6,14 @@ import {
|
||||
UMB_CURRENT_USER_MODAL,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
@customElement('umb-current-user-header-app')
|
||||
export class UmbCurrentUserHeaderAppElement extends UmbLitElement {
|
||||
@state()
|
||||
private _currentUser?: UmbLoggedInUser;
|
||||
|
||||
private _currentUserStore?: UmbCurrentUserStore;
|
||||
private _auth?: typeof UMB_AUTH.TYPE;
|
||||
private _modalContext?: UmbModalManagerContext;
|
||||
|
||||
constructor() {
|
||||
@@ -24,16 +23,16 @@ export class UmbCurrentUserHeaderAppElement extends UmbLitElement {
|
||||
this._modalContext = instance;
|
||||
});
|
||||
|
||||
this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (instance) => {
|
||||
this._currentUserStore = instance;
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this._auth = instance;
|
||||
this._observeCurrentUser();
|
||||
});
|
||||
}
|
||||
|
||||
private async _observeCurrentUser() {
|
||||
if (!this._currentUserStore) return;
|
||||
if (!this._auth) return;
|
||||
|
||||
this.observe(this._currentUserStore.currentUser, (currentUser) => {
|
||||
this.observe(this._auth.currentUser, (currentUser) => {
|
||||
this._currentUser = currentUser;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import type { UmbLoggedInUser } from './types.js';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
|
||||
export const UMB_CURRENT_USER_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbCurrentUserStore>('UmbCurrentUserStore');
|
||||
|
||||
export class UmbCurrentUserStore {
|
||||
#currentUser = new UmbObjectState<UmbLoggedInUser | undefined>(undefined);
|
||||
public readonly currentUser = this.#currentUser.asObservable();
|
||||
}
|
||||
@@ -1,4 +1,2 @@
|
||||
export * from './types.js';
|
||||
// TODO:Do not export store, but instead export future repository
|
||||
export * from './current-user.store.js';
|
||||
export * from './current-user-history.store.js';
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from '../../current-user.store.js';
|
||||
import type { UmbLoggedInUser } from '../../types.js';
|
||||
import { UMB_AUTH } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_APP } from '@umbraco-cms/backoffice/context';
|
||||
import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { css, CSSResultGroup, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
@@ -15,8 +13,6 @@ export class UmbCurrentUserModalElement extends UmbLitElement {
|
||||
@state()
|
||||
private _currentUser?: UmbLoggedInUser;
|
||||
|
||||
private _currentUserStore?: UmbCurrentUserStore;
|
||||
|
||||
#auth?: typeof UMB_AUTH.TYPE;
|
||||
|
||||
#appContext?: typeof UMB_APP.TYPE;
|
||||
@@ -24,8 +20,8 @@ export class UmbCurrentUserModalElement extends UmbLitElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (instance) => {
|
||||
this._currentUserStore = instance;
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this.#auth = instance;
|
||||
this._observeCurrentUser();
|
||||
});
|
||||
|
||||
@@ -41,9 +37,9 @@ export class UmbCurrentUserModalElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
private async _observeCurrentUser() {
|
||||
if (!this._currentUserStore) return;
|
||||
if (!this.#auth) return;
|
||||
|
||||
this.observe(this._currentUserStore.currentUser, (currentUser) => {
|
||||
this.observe(this.#auth.currentUser, (currentUser) => {
|
||||
this._currentUser = currentUser;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import type { UmbEntityBase } from '@umbraco-cms/backoffice/models';
|
||||
|
||||
export interface UserEntity extends UmbEntityBase {
|
||||
type: 'user';
|
||||
}
|
||||
|
||||
export type UserStatus = 'enabled' | 'inactive' | 'invited' | 'disabled';
|
||||
|
||||
export interface UmbLoggedInUser extends UserEntity {
|
||||
email: string;
|
||||
status: UserStatus;
|
||||
language: string;
|
||||
lastLoginDate?: string;
|
||||
lastLockoutDate?: string;
|
||||
lastPasswordChangeDate?: string;
|
||||
updateDate: string;
|
||||
createDate: string;
|
||||
failedLoginAttempts: number;
|
||||
userGroups: Array<string>;
|
||||
contentStartNodes: Array<string>;
|
||||
mediaStartNodes: Array<string>;
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from '../current-user.store.js';
|
||||
import type { UmbLoggedInUser } from '../types.js';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
@@ -8,6 +6,7 @@ import {
|
||||
UMB_CHANGE_PASSWORD_MODAL,
|
||||
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
@customElement('umb-user-profile-app-profile')
|
||||
export class UmbUserProfileAppProfileElement extends UmbLitElement {
|
||||
@@ -15,7 +14,7 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement {
|
||||
private _currentUser?: UmbLoggedInUser;
|
||||
|
||||
private _modalContext?: UmbModalManagerContext;
|
||||
private _currentUserStore?: UmbCurrentUserStore;
|
||||
private _auth?: typeof UMB_AUTH.TYPE;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -24,8 +23,8 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement {
|
||||
this._modalContext = instance;
|
||||
});
|
||||
|
||||
this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (instance) => {
|
||||
this._currentUserStore = instance;
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this._auth = instance;
|
||||
this._observeCurrentUser();
|
||||
});
|
||||
|
||||
@@ -33,9 +32,9 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
private async _observeCurrentUser() {
|
||||
if (!this._currentUserStore) return;
|
||||
if (!this._auth) return;
|
||||
|
||||
this.observe(this._currentUserStore.currentUser, (currentUser) => {
|
||||
this.observe(this._auth.currentUser, (currentUser) => {
|
||||
this._currentUser = currentUser;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { manifests as userManifests } from './users/manifests.js';
|
||||
import { manifests as userSectionManifests } from './user-section/manifests.js';
|
||||
import { manifests as currentUserManifests } from './current-user/manifests.js';
|
||||
|
||||
import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from './current-user/current-user.store.js';
|
||||
import {
|
||||
UmbCurrentUserHistoryStore,
|
||||
UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN,
|
||||
@@ -21,7 +20,6 @@ export const manifests = [...userGroupManifests, ...userManifests, ...userSectio
|
||||
export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => {
|
||||
extensionRegistry.registerMany(manifests);
|
||||
|
||||
new UmbContextProviderController(host, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, new UmbCurrentUserStore());
|
||||
new UmbUserItemStore(host);
|
||||
new UmbUserGroupItemStore(host);
|
||||
new UmbContextProviderController(
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from '../../current-user/current-user.store.js';
|
||||
import { getLookAndColorFromUserStatus } from '../../utils.js';
|
||||
import { UmbUserRepository } from '../repository/user.repository.js';
|
||||
import { UmbUserGroupInputElement } from '../../user-groups/components/input-user-group/user-group-input.element.js';
|
||||
@@ -24,16 +23,17 @@ import { UserResponseModel, UserStateModel } from '@umbraco-cms/backoffice/backe
|
||||
import { createExtensionClass } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UMB_AUTH, UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
@customElement('umb-user-workspace-editor')
|
||||
export class UmbUserWorkspaceEditorElement extends UmbLitElement {
|
||||
@state()
|
||||
private _currentUser?: any;
|
||||
private _currentUser?: UmbLoggedInUser;
|
||||
|
||||
@state()
|
||||
private _user?: UserResponseModel;
|
||||
|
||||
#currentUserStore?: UmbCurrentUserStore;
|
||||
#auth?: typeof UMB_AUTH.TYPE;
|
||||
#modalContext?: UmbModalManagerContext;
|
||||
#languages = []; //TODO Add languages
|
||||
#workspaceContext?: UmbUserWorkspaceContext;
|
||||
@@ -43,8 +43,8 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (store) => {
|
||||
this.#currentUserStore = store;
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this.#auth = instance;
|
||||
this.#observeCurrentUser();
|
||||
});
|
||||
|
||||
@@ -76,8 +76,8 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
#observeCurrentUser() {
|
||||
if (!this.#currentUserStore) return;
|
||||
this.observe(this.#currentUserStore.currentUser, (currentUser) => (this._currentUser = currentUser));
|
||||
if (!this.#auth) return;
|
||||
this.observe(this.#auth.currentUser, (currentUser) => (this._currentUser = currentUser));
|
||||
}
|
||||
|
||||
#onUserStatusChange() {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
import type { IUmbAuth } from './auth.interface.js';
|
||||
import {
|
||||
BaseTokenRequestHandler,
|
||||
BasicQueryStringUtils,
|
||||
@@ -81,7 +80,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 implements IUmbAuth {
|
||||
export class UmbAuthFlow {
|
||||
// handlers
|
||||
readonly #notifier: AuthorizationNotifier;
|
||||
readonly #authorizationHandler: RedirectRequestHandler;
|
||||
@@ -164,7 +163,6 @@ export class UmbAuthFlow implements IUmbAuth {
|
||||
if (response.isValid()) {
|
||||
this.#accessTokenResponse = response;
|
||||
this.#refreshToken = this.#accessTokenResponse.refreshToken;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +223,7 @@ export class UmbAuthFlow implements IUmbAuth {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will check if the user is logged in by validting the timestamp of the stored token.
|
||||
* This method will check 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.
|
||||
|
||||
46
src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts
Normal file
46
src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { IUmbAuth } from './auth.interface.js';
|
||||
import { UmbAuthFlow } from './auth-flow.js';
|
||||
import { UmbLoggedInUser } from './types.js';
|
||||
import { UserResource } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
|
||||
import { ReplaySubject } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
|
||||
export class UmbAuthContext implements IUmbAuth {
|
||||
#currentUser = new UmbObjectState<UmbLoggedInUser | undefined>(undefined);
|
||||
readonly currentUser = this.#currentUser.asObservable();
|
||||
readonly isLoggedIn = new ReplaySubject<boolean>(1);
|
||||
|
||||
#host;
|
||||
#authFlow;
|
||||
|
||||
constructor(host: UmbControllerHostElement, authFlow: UmbAuthFlow) {
|
||||
this.#host = host;
|
||||
this.#authFlow = authFlow;
|
||||
|
||||
this.isLoggedIn.subscribe((isLoggedIn) => {
|
||||
if (isLoggedIn) {
|
||||
this.fetchCurrentUser();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fetchCurrentUser(): Promise<UmbLoggedInUser | undefined> {
|
||||
const { data } = await tryExecuteAndNotify(this.#host, UserResource.getUserCurrent());
|
||||
|
||||
if (!data) return;
|
||||
|
||||
this.#currentUser.next(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
performWithFreshTokens(): Promise<string> {
|
||||
return this.#authFlow.performWithFreshTokens();
|
||||
}
|
||||
|
||||
signOut(): Promise<void> {
|
||||
return this.#authFlow.signOut();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
import type { UmbLoggedInUser } from './types.js';
|
||||
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
|
||||
export interface IUmbAuth {
|
||||
/**
|
||||
* Get the current user's access token.
|
||||
@@ -10,6 +13,16 @@ export interface IUmbAuth {
|
||||
*/
|
||||
performWithFreshTokens(): Promise<string>;
|
||||
|
||||
/**
|
||||
* Get the current user model of the current user.
|
||||
*/
|
||||
get currentUser(): Observable<UmbLoggedInUser | undefined>;
|
||||
|
||||
/**
|
||||
* Make a server request for the current user and save the state
|
||||
*/
|
||||
fetchCurrentUser(): Promise<UmbLoggedInUser | undefined>;
|
||||
|
||||
/**
|
||||
* Sign out the current user.
|
||||
*/
|
||||
|
||||
7
src/Umbraco.Web.UI.Client/src/shared/auth/auth.token.ts
Normal file
7
src/Umbraco.Web.UI.Client/src/shared/auth/auth.token.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { IUmbAuth } from './auth.interface.js';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export const UMB_AUTH = new UmbContextToken<IUmbAuth>(
|
||||
'UmbAuth',
|
||||
'An instance of UmbAuthFlow that should be shared across the app.'
|
||||
);
|
||||
@@ -1,10 +1,6 @@
|
||||
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 { UmbAuthContext } from './auth.context.js';
|
||||
|
||||
export const UMB_AUTH = new UmbContextToken<IUmbAuth>(
|
||||
'UmbAuth',
|
||||
'An instance of UmbAuthFlow that should be shared across the app.'
|
||||
);
|
||||
export * from './types.js';
|
||||
export * from './auth.token.js';
|
||||
|
||||
1
src/Umbraco.Web.UI.Client/src/shared/auth/types.ts
Normal file
1
src/Umbraco.Web.UI.Client/src/shared/auth/types.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type { CurrentUserResponseModel as UmbLoggedInUser } from '@umbraco-cms/backoffice/backend-api';
|
||||
Reference in New Issue
Block a user