diff --git a/package.json b/package.json index fd1945e..75d8775 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "license": "MIT", "scripts": { "start": "ng serve", + "start:https": "ng serve --ssl true --host 0.0.0.0 --port 8443", "build": "ng build", "lint": "ng lint", "json:server": "json-server --delay 3000 --watch db.json", diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index db45c8d..16279ce 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -7,5 +7,6 @@ export const ROUTES: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'home', loadChildren: './home/home.module#HomeModule', data: { state: 'home' } }, { path: 'demo', loadChildren: './demo/demo.module#DemoModule', data: { state: 'demo' } }, + { path: 'oauth', loadChildren: './oauth/oauth.module#OAuthModule', data: { state: 'oauth' } }, { path: '**', component: PageNotFoundComponent } ]; diff --git a/src/app/appcommon/security/OAuth.ts b/src/app/appcommon/security/OAuth.ts new file mode 100644 index 0000000..5e8b376 --- /dev/null +++ b/src/app/appcommon/security/OAuth.ts @@ -0,0 +1,51 @@ +export interface IOAuthOptions { + AUTH_URL: string; + CLIENT_ID: string; + SCOPE: string[]; + OAUTH_REDIRECT_URI: string; +} + +interface IOAuth { + oAuthLogin(url: string): Promise; +} + +class OAuthBrowser implements IOAuth { + options: IOAuthOptions; + constructor(options: IOAuthOptions) { + this.options = options; + } + + public oAuthLogin(url: string): Promise { + return new Promise(function(resolve, reject) { + console.log('OAuth URL : ' + url); + window.location.href = url; + }); + } +} + +export class OAuth { + private options: IOAuthOptions; + private APP_SCOPE_DELIMITER = ' '; + private _oAuthClient: IOAuth; + private url: string; + + constructor(options: IOAuthOptions) { + this.options = options; + this._oAuthClient = new OAuthBrowser(options); + this.url = `${options.AUTH_URL}?response_type=token&client_id=${options.CLIENT_ID}&redirect_uri=${ + options.OAUTH_REDIRECT_URI + }&scope=${options.SCOPE.join(this.APP_SCOPE_DELIMITER)}`; + } + + authenticate(): Promise { + return this._oAuthClient.oAuthLogin(this.url); + } + + getClientId(): string { + return this.options.CLIENT_ID; + } + + getRedirectUri(): string { + return this.options.OAUTH_REDIRECT_URI; + } +} diff --git a/src/app/appcommon/security/index.ts b/src/app/appcommon/security/index.ts new file mode 100644 index 0000000..2d5c6eb --- /dev/null +++ b/src/app/appcommon/security/index.ts @@ -0,0 +1 @@ +export * from './OAuth'; diff --git a/src/app/appcommon/services/app.service.ts b/src/app/appcommon/services/app.service.ts index f38155e..aa30b08 100644 --- a/src/app/appcommon/services/app.service.ts +++ b/src/app/appcommon/services/app.service.ts @@ -44,7 +44,7 @@ export class AppState { * Use our state getter for the clone. */ const state = this.state; - return state.hasOwnProperty(prop) ? state[prop] : state; + return state.hasOwnProperty(prop) ? state[prop] : null; } public set(prop: string, value: any) { diff --git a/src/app/components/header/header.component.ts b/src/app/components/header/header.component.ts index fa4b799..55cf0e8 100644 --- a/src/app/components/header/header.component.ts +++ b/src/app/components/header/header.component.ts @@ -1,5 +1,7 @@ import { MenuItem } from 'primeng/primeng'; import { Component, OnInit } from '@angular/core'; +import { OAuth } from '../../appcommon/security'; +import { environment } from '../../../environments/environment'; @Component({ selector: 'app-header', @@ -21,6 +23,19 @@ export class HeaderComponent implements OnInit { items: [{ label: 'Project' }, { label: 'Other' }] }, { label: 'Open', routerLink: ['pagename'] }, + { + label: 'Google OAuth', + command: event => { + event.originalEvent.preventDefault(); + const oAuth = new OAuth({ + AUTH_URL: environment.AUTH_URL, + CLIENT_ID: environment.OAUTH_CLIENT_ID, + SCOPE: ['profile'], + OAUTH_REDIRECT_URI: window.location.origin + '/oauth/' + }); + oAuth.authenticate(); + } + }, { label: 'Quit', routerLink: ['pagename'] } ] }, diff --git a/src/app/oauth/components/oauth.component.html b/src/app/oauth/components/oauth.component.html new file mode 100644 index 0000000..ea91afb --- /dev/null +++ b/src/app/oauth/components/oauth.component.html @@ -0,0 +1,12 @@ +
+
+ Your Google Access Token : + {{accessToken}} +
+
+
+
+ User Details : +
{{userInfo | json}}
+
+
\ No newline at end of file diff --git a/src/app/oauth/components/oauth.component.scss b/src/app/oauth/components/oauth.component.scss new file mode 100644 index 0000000..e5c9985 --- /dev/null +++ b/src/app/oauth/components/oauth.component.scss @@ -0,0 +1,10 @@ +.oauth-home { + padding: 20px; + + .information { + background-color: #cdcdcd; + border: solid 1px #a0a0a0; + border-radius: 5px; + padding: 10px; + } +} diff --git a/src/app/oauth/components/oauth.component.ts b/src/app/oauth/components/oauth.component.ts new file mode 100644 index 0000000..71cd478 --- /dev/null +++ b/src/app/oauth/components/oauth.component.ts @@ -0,0 +1,47 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { AppState } from '../../appcommon/services/app.service'; +import { UserInfoService } from '../services/userinfo.service'; + +@Component({ + selector: 'app-oauth', + templateUrl: './oauth.component.html', + styleUrls: ['./oauth.component.scss'] +}) +export class OAuthComponent implements OnInit { + userInfo: any; + accessToken: string; + + constructor( + private appState: AppState, + private activeRoute: ActivatedRoute, + private router: Router, + private service: UserInfoService + ) { + this.activeRoute.params.subscribe(params => { + const url = window.location.href; + if (url.split('#').length > 1) { + const responseParameters = url.split('#')[1].split('&'); + const parsedResponse = {}; + for (let i = 0; i < responseParameters.length; i++) { + parsedResponse[responseParameters[i].split('=')[0]] = responseParameters[i].split('=')[1]; + } + if (parsedResponse['access_token'] !== undefined && parsedResponse['access_token'] !== null) { + this.appState.set('accessToken', parsedResponse['access_token']); + this.router.navigate(['oauth']); + } + } + }); + } + + ngOnInit() { + this.accessToken = this.appState.get('accessToken'); + if (this.accessToken) { + this.service.getUserInfo(this.accessToken).subscribe(data => { + this.userInfo = data; + }); + } else { + this.router.navigate(['home']); + } + } +} diff --git a/src/app/oauth/oauth.module.ts b/src/app/oauth/oauth.module.ts new file mode 100644 index 0000000..9551627 --- /dev/null +++ b/src/app/oauth/oauth.module.ts @@ -0,0 +1,15 @@ +import { AppcommonModule } from './../appcommon/appcommon.module'; +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Routes, RouterModule } from '@angular/router'; +import { OAuthComponent } from './components/oauth.component'; +import { UserInfoService } from './services/userinfo.service'; + +const routes: Routes = [{ path: '', component: OAuthComponent }]; + +@NgModule({ + imports: [CommonModule, AppcommonModule, RouterModule.forChild(routes)], + providers: [UserInfoService], + declarations: [OAuthComponent] +}) +export class OAuthModule {} diff --git a/src/app/oauth/services/userinfo.service.ts b/src/app/oauth/services/userinfo.service.ts new file mode 100644 index 0000000..35331d4 --- /dev/null +++ b/src/app/oauth/services/userinfo.service.ts @@ -0,0 +1,12 @@ +import { Observable } from 'rxjs/Observable'; +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +@Injectable() +export class UserInfoService { + constructor(private http: HttpClient) {} + + public getUserInfo(accessToken): Observable { + return this.http.post(`https://www.googleapis.com/oauth2/v3/userinfo?access_token=${accessToken}`, ''); + } +} diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 37351d0..9d9847f 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,4 +1,6 @@ export const environment = { production: true, - LOG_LEVEL: 'warn' + LOG_LEVEL: 'warn', + AUTH_URL: 'https://accounts.google.com/o/oauth2/v2/auth', + OAUTH_CLIENT_ID: '603712460284-9c20vfg98ra1cecdhu2r84d4ij6erpcr.apps.googleusercontent.com' }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 4fd2d82..97a6328 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -5,5 +5,7 @@ export const environment = { production: false, - LOG_LEVEL: 'debug' + LOG_LEVEL: 'debug', + AUTH_URL: 'https://accounts.google.com/o/oauth2/v2/auth', + OAUTH_CLIENT_ID: '603712460284-9c20vfg98ra1cecdhu2r84d4ij6erpcr.apps.googleusercontent.com' };