Skip to content

Commit

Permalink
feat(auth): add authentication form and service
Browse files Browse the repository at this point in the history
  • Loading branch information
mbarbeau committed Aug 7, 2017
1 parent da3509c commit 468b5c8
Show file tree
Hide file tree
Showing 26 changed files with 556 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/demo-app/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<igo-spinner igoSpinnerBinding></igo-spinner>
<igo-message-center></igo-message-center>

<igo-auth-form></igo-auth-form>
<md-sidenav-container>

<md-sidenav
Expand Down
15 changes: 14 additions & 1 deletion src/demo-app/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.

import { SearchSourcesOptions, LanguageOptions } from '../../lib';
import { SearchSourcesOptions, LanguageOptions, AuthOptions } from '../../lib';

interface Environment {
production: boolean;
igo: {
searchSources?: SearchSourcesOptions;
language?: LanguageOptions;
auth?: AuthOptions;
};
};

Expand All @@ -23,6 +24,18 @@ export const environment: Environment = {
},
language: {
prefix: './assets/locale/'
},
auth: {
url: 'http://localhost:8000/users',
tokenKey: 'id_token_igo',
google: {
apiKey: 'AIzaSyCbc-E35ZNqAjPvpbr30bAXwfcQoq5XLBs',
clientId: '467961599657-f7lebhfn3oposibnrvlgjl7ffglgr2go.apps.googleusercontent.com'
},
facebook: {
apiKey: '1989457734616371',
enabled: false
}
}
}
};
5 changes: 5 additions & 0 deletions src/lib/auth/auth-form/auth-facebook.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div scope="public_profile,email"
class="fb-login-button" data-max-rows="1" data-size="large"
data-button-type="continue_with" data-show-faces="false"
data-auto-logout-link="false" data-use-continue-as="false">
</div>
3 changes: 3 additions & 0 deletions src/lib/auth/auth-form/auth-facebook.component.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.fb-login-button {
padding: 10px 0;
}
56 changes: 56 additions & 0 deletions src/lib/auth/auth-form/auth-facebook.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Component, ChangeDetectionStrategy, ApplicationRef } from '@angular/core';

import { ConfigService } from '../../core';
import { AuthService, AuthFacebookOptions } from '../shared';

@Component({
selector: 'igo-auth-facebook',
templateUrl: './auth-facebook.component.html',
styleUrls: ['./auth-facebook.component.styl'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AuthFacebookComponent {

private options: AuthFacebookOptions;

constructor(private authService: AuthService,
private config: ConfigService,
private appRef: ApplicationRef) {

this.options = this.config.getConfig('auth.google') || {};

if (this.options.apiKey) {
this.loadSDKFacebook();
}
}

private subscribeEvents() {
window['FB'].Event.subscribe('auth.statusChange', (rep) => {
this.statusChangeCallback(rep);
});
}

private statusChangeCallback(response) {
if (response.status === 'connected') {
const accessToken = response.authResponse.accessToken;
this.login(accessToken);
}
}

private login(token) {
this.authService.loginWithToken(token, 'facebook').subscribe(() => {
this.appRef.tick();
});
}

private loadSDKFacebook() {
const urlSDK = 'https://connect.facebook.net/fr_CA/sdk.js#xfbml=1&version=v2.9';
var js, fjs = document.getElementsByTagName('script')[0];
if (document.getElementById('facebook-jssdk')) return;
js = document.createElement('script');
js.id = 'facebook-jssdk';
js.src = `${urlSDK}&appId=${this.options.apiKey}`;
js.onload = () => {this.subscribeEvents();};
fjs.parentNode.insertBefore(js, fjs);
}
}
9 changes: 9 additions & 0 deletions src/lib/auth/auth-form/auth-form.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div *ngIf="!auth.logged" class="backgroundDisable"></div>

<div *ngIf="!auth.logged" class="login center-block">
<h1>{{'igo.auth.connection' | translate}}</h1>

<igo-auth-google *ngIf="options.google && options.google.enabled !== false"></igo-auth-google>
<igo-auth-facebook *ngIf="options.facebook && options.facebook.enabled !== false"></igo-auth-facebook>
<igo-auth-intern *ngIf="!options.intern || options.intern.enabled !== false"></igo-auth-intern>
</div>
35 changes: 35 additions & 0 deletions src/lib/auth/auth-form/auth-form.component.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
$colorFont = #888;

:host {
z-index: 999;
}

div.login {
z-index: 200;
width: 90%;
min-width: 360px;
max-width: 600px;
padding: 25px 50px;
border: 1px solid;
background-color: #fff;
border-color: $colorFont;
}

.center-block {
position: fixed;
top: 20%;
left: 50%;
transform: translate(-50%, 0);
}


.backgroundDisable {
position: fixed;
top: 0;
left: 0;
background: #000;
opacity: 0.8;
z-index: 100;
height: 100%;
width: 100%;
}
21 changes: 21 additions & 0 deletions src/lib/auth/auth-form/auth-form.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';

import { ConfigService } from '../../core';
import { AuthService, AuthOptions } from "../shared";

@Component({
selector: 'igo-auth-form',
templateUrl: './auth-form.component.html',
styleUrls: ['./auth-form.component.styl'],
changeDetection: ChangeDetectionStrategy.Default
})
export class AuthFormComponent {
private options: AuthOptions;

constructor(
public auth: AuthService,
private config: ConfigService
) {
this.options = this.config.getConfig('auth') || {};
}
}
1 change: 1 addition & 0 deletions src/lib/auth/auth-form/auth-google.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="g-signin2 google-login-button" data-height="40" data-width="265" data-longtitle="true">
3 changes: 3 additions & 0 deletions src/lib/auth/auth-form/auth-google.component.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.google-login-button {
padding: 10px 0;
}
82 changes: 82 additions & 0 deletions src/lib/auth/auth-form/auth-google.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Component, ChangeDetectionStrategy, ApplicationRef } from '@angular/core';

import { ConfigService } from '../../core';
import { AuthService, AuthGoogleOptions } from '../shared';

@Component({
selector: 'igo-auth-google',
templateUrl: './auth-google.component.html',
styleUrls: ['./auth-google.component.styl'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AuthGoogleComponent {

private options: AuthGoogleOptions;

constructor(private authService: AuthService,
private config: ConfigService,
private appRef: ApplicationRef) {

this.options = this.config.getConfig('auth.google') || {};

if (this.options.apiKey && this.options.clientId) {
this.loadSDKGoogle();
this.loadPlatform();
}
}

public handleSignInClick() {
window['gapi'].auth2.getAuthInstance().signIn();
}

public handleSignOutClick() {
window['gapi'].auth2.getAuthInstance().signOut();
}

private handleClientLoad() {
window['gapi'].load('client:auth2', () => this.initClient());
}

private initClient() {
window['gapi'].client.init({
apiKey: this.options.apiKey,
clientId: this.options.clientId,
discoveryDocs: ["https://people.googleapis.com/$discovery/rest?version=v1"],
scope: 'profile'
}).then(() => {
this.handleSignOutClick();
window['gapi'].auth2.getAuthInstance().isSignedIn.listen((rep) => {
this.updateSigninStatus(rep)
});
});
}

private updateSigninStatus(isSignedIn) {
if (isSignedIn) {
this.login(window['gapi'].client.getToken().access_token);
}
}

private login(token) {
this.authService.loginWithToken(token, 'google').subscribe(() => {
this.appRef.tick();
});
}

private loadSDKGoogle() {
var js, fjs = document.getElementsByTagName('script')[0];
js = document.createElement('script');
js.id = 'google-jssdk';
js.src = 'https://apis.google.com/js/api.js';
js.onload = () => {this.handleClientLoad();};
fjs.parentNode.insertBefore(js, fjs);
}

private loadPlatform() {
var js, fjs = document.getElementsByTagName('script')[0];
js = document.createElement('script');
js.id = 'google-platform';
js.src = 'https://apis.google.com/js/platform.js';
fjs.parentNode.insertBefore(js, fjs);
}
}
12 changes: 12 additions & 0 deletions src/lib/auth/auth-form/auth-intern.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<form [formGroup]="form" role="form">
<md-input-container class="example-full-width">
<input mdInput required placeholder="{{'igo.auth.user' | translate}}" formControlName="username">
</md-input-container>

<md-input-container class="example-full-width">
<input mdInput required type="password" placeholder="{{'igo.auth.password' | translate}}" formControlName="password">
</md-input-container>

<button md-raised-button (click)="login(form.value)" [disabled]="!form.valid">{{'igo.auth.login' | translate}}</button>
<div *ngIf="error"><font size="3" color="red">{{error}}</font></div>
</form>
Empty file.
41 changes: 41 additions & 0 deletions src/lib/auth/auth-form/auth-intern.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Validators, FormGroup, FormBuilder } from "@angular/forms";
import { AuthService } from "../shared/auth.service";

@Component({
selector: 'igo-auth-intern',
templateUrl: './auth-intern.component.html',
styleUrls: ['./auth-intern.component.styl'],
changeDetection: ChangeDetectionStrategy.Default
})
export class AuthInternComponent {
public error: string = "";
private form: FormGroup;

constructor(
public auth: AuthService,
fb: FormBuilder
) {
this.form = fb.group({
username: ["", Validators.required],
password: ["", Validators.required]
});
}


protected login(values: any) {
this.auth.login(values.username, values.password)
.subscribe(
() => {},
(errors: any) => {
let message = "";
for (let err in errors) {
if (!errors.hasOwnProperty(err)) { continue; }
message += errors[err]['message'] + '\n';
}
this.error = message;
}
);
return false;
}
}
4 changes: 4 additions & 0 deletions src/lib/auth/auth-form/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './auth-form.component';
export * from './auth-intern.component';
export * from './auth-facebook.component';
export * from './auth-google.component';
5 changes: 5 additions & 0 deletions src/lib/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { AuthHttp } from 'angular2-jwt';

export * from './shared';
export * from './auth-form';
export * from './module';
52 changes: 52 additions & 0 deletions src/lib/auth/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { NgModule, ModuleWithProviders } from '@angular/core';
import { Http, RequestOptions } from '@angular/http';

import { AuthHttp, AuthConfig } from 'angular2-jwt';

import { IgoSharedModule } from '../shared';
import { AuthFormComponent,
AuthInternComponent,
AuthFacebookComponent,
AuthGoogleComponent
} from './auth-form';

import { AuthService } from './shared';


export function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig({
headerName: 'Authorization',
headerPrefix: '',
tokenName: 'id_token_igo', // TODO : move in config
tokenGetter: (() => localStorage.getItem('id_token_igo')),
noJwtError: true
}), http, options);
}

@NgModule({
imports: [IgoSharedModule],
declarations: [
AuthFormComponent,
AuthInternComponent,
AuthFacebookComponent,
AuthGoogleComponent
],
exports: [AuthFormComponent]
})


export class IgoAuthModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: IgoAuthModule,
providers: [
AuthService,
{
provide: AuthHttp,
useFactory: authHttpServiceFactory,
deps: [Http, RequestOptions]
}
]
};
}
}
Loading

0 comments on commit 468b5c8

Please sign in to comment.