Skip to content

Commit

Permalink
Feature/azure sso (#332) (#333)
Browse files Browse the repository at this point in the history
* WIP

* working login/logout with issues

* fixed formatting

* Too many imports for reasonable testing

* remove google verification file
  • Loading branch information
UsiDiamond authored Jul 25, 2023
1 parent 5585e65 commit e4cafad
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 51 deletions.
33 changes: 33 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"@angular/platform-browser": "^16.1.4",
"@angular/platform-browser-dynamic": "^16.1.4",
"@angular/router": "^16.1.4",
"@azure/msal-angular": "^3.0.0-beta.0",
"@azure/msal-browser": "^3.0.0-beta.0",
"@ng-bootstrap/ng-bootstrap": "^15.1.0",
"bootstrap": "^5.3.0",
"express-rate-limit": "^6.7.0",
Expand Down
10 changes: 10 additions & 0 deletions src/app/app.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,13 @@ button {
.navigation button {
font-weight: bold;
}

.login-button {
color: white;
font-weight: bold;
}

.logout-button {
color: white;
font-weight: bold;
}
21 changes: 21 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,28 @@
alt="Neurodiversity in Buisness Logo"
/>
</div>

<div class="col" style="text-align: right">
<div>
<button
class="login-button btn btn-primary"
*ngIf="!loginDisplay"
(click)="loginRedirect()"
>
Login
</button>
<p *ngIf="loginDisplay">
Welcome {{ username }}
<button
class="logout-button btn btn-secondary"
*ngIf="loginDisplay"
(click)="logout()"
>
Logout
</button>
</p>
</div>
<br /><br />
<div [(ngbCollapse)]="isMenuCollapsed" class="collapse navbar-collapse">
<ul
[keyboard]="true"
Expand Down
27 changes: 0 additions & 27 deletions src/app/app.component.spec.ts

This file was deleted.

107 changes: 104 additions & 3 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,52 @@ import {
AfterViewInit,
Component,
ElementRef,
Inject,
OnDestroy,
OnInit,
ViewChild,
} from '@angular/core';
import { Router } from '@angular/router';
import { DisplayContentService } from './display-content.service';

import {
MsalService,
MsalBroadcastService,
MSAL_GUARD_CONFIG,
MsalGuardConfiguration,
} from '@azure/msal-angular';
import {
AuthenticationResult,
InteractionStatus,
PopupRequest,
RedirectRequest,
EventMessage,
EventType,
} from '@azure/msal-browser';
import { Subject } from 'rxjs/internal/Subject';
import { filter, takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit, AfterViewInit {
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('nav') nav: ElementRef;
title = 'Neurodiversity in Business';
navActiveId = 1;
isContentShown = true;
isMenuCollapsed = window.innerWidth <= 991;
loginDisplay = false;
username = "";
private readonly _destroying$ = new Subject<void>();

public isMobileLayout = false;

constructor(
private displayContentService: DisplayContentService,
private router: Router
private router: Router,
@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration,
private authService: MsalService,
private msalBroadcastService: MsalBroadcastService
) {}

ngOnInit() {
Expand All @@ -34,6 +58,41 @@ export class AppComponent implements OnInit, AfterViewInit {
this.isMobileLayout = window.innerWidth <= 991;
this.isMenuCollapsed = this.isMobileLayout;
};
this.setLoginDisplay();
this.authService.handleRedirectObservable().subscribe((res) => {
this.isContentShown = true;
this.username = this.authService.instance.getActiveAccount()?.name!;
console.log(res);
});

this.authService.instance.enableAccountStorageEvents(); // Optional - This will enable ACCOUNT_ADDED and ACCOUNT_REMOVED events emitted when a user logs in or out of another tab or window
this.msalBroadcastService.msalSubject$
.pipe(
filter(
(msg: EventMessage) =>
msg.eventType === EventType.ACCOUNT_ADDED ||
msg.eventType === EventType.ACCOUNT_REMOVED
)
)
.subscribe((result: EventMessage) => {
if (this.authService.instance.getAllAccounts().length === 0) {
window.location.pathname = '/';
} else {
this.setLoginDisplay();
}
});

this.msalBroadcastService.inProgress$
.pipe(
filter(
(status: InteractionStatus) => status === InteractionStatus.None
),
takeUntil(this._destroying$)
)
.subscribe(() => {
this.setLoginDisplay();
this.checkAndSetActiveAccount();
});
}

ngAfterViewInit(): void {
Expand All @@ -58,7 +117,49 @@ export class AppComponent implements OnInit, AfterViewInit {
},
});
}
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
}
checkAndSetActiveAccount() {
/**
* If no active account set but there are accounts signed in, sets first account to active account
* To use active account set here, subscribe to inProgress$ first in your component
* Note: Basic usage demonstrated. Your app may require more complicated account selection logic
*/
let activeAccount = this.authService.instance.getActiveAccount();

if (
!activeAccount &&
this.authService.instance.getAllAccounts().length > 0
) {
let accounts = this.authService.instance.getAllAccounts();
this.authService.instance.setActiveAccount(accounts[0]);
}
}
loginRedirect() {
if (this.msalGuardConfig.authRequest) {
this.authService.loginRedirect({
...this.msalGuardConfig.authRequest,
} as RedirectRequest);
} else {
this.authService.loginRedirect();
}
}

logout(popup?: boolean) {
if (popup) {
this.authService.logoutPopup({
mainWindowRedirectUri: '/',
});
} else {
this.authService.logoutRedirect();
}
}

ngOnDestroy(): void {
this._destroying$.next(undefined);
this._destroying$.complete();
}
toggleContent(flag: string) {
if (flag == 'hide') {
this.isContentShown = false;
Expand Down
103 changes: 101 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,82 @@ import { PrivacyPolicyComponent } from './privacy-policy/privacy-policy.componen
import { CookiePolicyComponent } from './cookie-policy/cookie-policy.component';
import { SlaveryPolicyComponent } from './slavery-policy/slavery-policy.component';
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
import {
MsalInterceptorConfiguration,
MsalGuardConfiguration,
MsalModule,
MSAL_GUARD_CONFIG,
MSAL_INSTANCE,
MSAL_INTERCEPTOR_CONFIG,
MsalBroadcastService,
MsalGuard,
MsalInterceptor,
MsalService,
MsalRedirectComponent,
} from '@azure/msal-angular';
import {
LogLevel,
IPublicClientApplication,
PublicClientApplication,
BrowserCacheLocation,
InteractionType,
} from '@azure/msal-browser';
import { environment } from 'src/environments/environment';
import { HTTP_INTERCEPTORS } from '@angular/common/http';

const isIE =
window.navigator.userAgent.indexOf('MSIE ') > -1 ||
window.navigator.userAgent.indexOf('Trident/') > -1; // Remove this line to use Angular Universal

export function loggerCallback(logLevel: LogLevel, message: string) {
console.log(message);
}

export function MSALInstanceFactory(): IPublicClientApplication {
return new PublicClientApplication({
auth: {
clientId: environment.msalConfig.auth.clientId,
authority: environment.msalConfig.auth.authority,
redirectUri: '/',
postLogoutRedirectUri: '/',
},
cache: {
cacheLocation: BrowserCacheLocation.LocalStorage,
storeAuthStateInCookie: isIE, // set to true for IE 11. Remove this line to use Angular Universal
},
system: {
allowNativeBroker: false, // Disables WAM Broker
loggerOptions: {
loggerCallback,
logLevel: LogLevel.Info,
piiLoggingEnabled: false,
},
},
});
}

export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
const protectedResourceMap = new Map<string, Array<string>>();
protectedResourceMap.set(
environment.apiConfig.uri,
environment.apiConfig.scopes
);

return {
interactionType: InteractionType.Redirect,
protectedResourceMap,
};
}

export function MSALGuardConfigFactory(): MsalGuardConfiguration {
return {
interactionType: InteractionType.Redirect,
authRequest: {
scopes: [...environment.apiConfig.scopes],
},
loginFailedRoute: '/',
};
}

@NgModule({
declarations: [
Expand All @@ -41,9 +117,32 @@ import { HashLocationStrategy, LocationStrategy } from '@angular/common';
NgbModule,
NgbCarouselModule,
PdfViewerModule,
MsalModule,
],
exports: [],
providers: [{ provide: LocationStrategy, useClass: HashLocationStrategy }],
bootstrap: [AppComponent],
providers: [
{ provide: LocationStrategy, useClass: HashLocationStrategy },
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true,
},
{
provide: MSAL_INSTANCE,
useFactory: MSALInstanceFactory,
},
{
provide: MSAL_GUARD_CONFIG,
useFactory: MSALGuardConfigFactory,
},
{
provide: MSAL_INTERCEPTOR_CONFIG,
useFactory: MSALInterceptorConfigFactory,
},
MsalService,
MsalGuard,
MsalBroadcastService,
],
bootstrap: [AppComponent, MsalRedirectComponent, HomeComponent],
})
export class AppModule {}
Loading

0 comments on commit e4cafad

Please sign in to comment.