Adding LoginFacebookComponent

It's time to switch to Angular. From Solution Explorer, right-click to the /ClientApp/app/components/login/ folder, add a new login.facebook.component.ts file, and fill it with the following content:

import { Component, Inject, OnInit, NgZone, PLATFORM_ID } from "@angular/core";
import { isPlatformBrowser } from '@angular/common';
import { HttpClient } from "@angular/common/http";
import { Router } from "@angular/router";
import { AuthService } from '../../services/auth.service';

// declare these vars here
// to let the TS compiler know that they exist
declare var window: any;
declare var FB: any;

@Component({
selector: "login-facebook",
templateUrl: "./login.facebook.component.html"
})

export class LoginFacebookComponent implements OnInit {

constructor(
private http: HttpClient,
private router: Router,
private authService: AuthService,
// inject the local zone
private zone: NgZone,
@Inject(PLATFORM_ID) private platformId: any,
@Inject('BASE_URL') private baseUrl: string) {
}

ngOnInit() {
if (!isPlatformBrowser(this.platformId)) {
return;
}

if (typeof (FB) === 'undefined') {

// if the FB oject is undefined,
// it means that it's the first time
// we visit this page, hence we need
// to initialize the Facebook SDK
window.fbAsyncInit = () =>

// be sure to do this within
// the local zone, or Angular will be
// unable to find the local references
this.zone.run(() => {
FB.init({
appId: '---YOUR-APP-ID---',
xfbml: true,
version: 'v2.10'
});
FB.AppEvents.logPageView();

// this will trigger right after the user
// completes the FB SDK Auth roundtrip successfully
FB.Event.subscribe('auth.statusChange', (
(result: any) => {
console.log("FB auth status changed");
console.log(result);
if (result.status === 'connected') {
// login successful
console.log('Connected to Facebook.');
this.onConnect(result.authResponse.accessToken);
}
})
);
});

// Load the SDK js library (only once)
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) { return; }
js = d.createElement(s); js.id = id;
(<any>js).src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode!.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

}
else {

// Reload the FB login button
window.FB.XFBML.parse();

// if the user is still connected, log him off.
FB.getLoginStatus(function (response: any) {
if (response.status === 'connected') {
FB.logout(function (res: any) {
// do nothing
});
}
});

}
}

// this method will be executed
// upon the user FB SDK Auth roundtrip completion
// to create/login the local user
onConnect(accessToken: string) {
// call TokenController and register/login
var url = this.baseUrl + "api/token/facebook";
var data = {
access_token: accessToken,
client_id: this.authService.clientId
};
this.http.post<TokenResponse>(
url, data)
.subscribe(res => {
if (res) {
console.log('Login successful.');
console.log(res);
// store user login data
this.authService.setAuth(res);

// redirect user to home
this.router.navigate(["home"]);
}
else {
console.log("Authentication failed");
}
}, error => console.log(error));
}
}

There are four highlighted blocks of code here. Let's see what they do:

  • Block #1: We declare two variables of any type here, so we can use them within the rest of the component without triggering the compiler. Alternatively, we can have the Facebook SDK typings added to our project or (even better) use one of the many Facebook SDK TypeScript wrappers that can be easily found on GitHub. We didn't do that because we want to be as lightweight and unobtrusive as possible; it's just a demonstration of how we can implement it, after all. We'll leave the reader the chance and the fun to further improve it.
  • Block #2: This is where we put the Facebook SDK official code that we've seen when we created the Facebook App; since it will have a permanent effect on the client, it will be executed only upon the first load; otherwise, Block #3 will be executed instead. If we don't consider the comments, the source code is almost identical to the suggested one, except for a couple of small modifications to make it compatible with our Angular application:
    • The whole fbAsyncInit event handler has been wrapped within the main Angular zone so that the component context will be preserved and the local function references will work. Okay, that's good to hear...except that we don't know what an Angular zone is yet! Don't worry, we'll talk more about that later on.
    • We added a subscription to the auth.statusChange FB event, that will trigger every time the user status changes from connected to disconnected (and vice versa) to our Facebook app using the Facebook SDK. That's the most convenient way to know when the login round trip has been concluded successfully and we can proceed with registering and/or authenticating the user locally.
  • Block #3: This is what happens when the user comes back here after a successful (or not successful) login; we refresh the Facebook button skin, and we log out the user from our FB App if he's still logged in. The logic behind this conditional logout is very simple--the login page is unaccessible by design for our local logged-in users, hence if a user comes here, it should always be treated as anonymous, even by the FB app.
  • Block #4: The onConnect() method gets called upon each successful login to the FB app, and it's entrusted with three main tasks: passing the OAuth2 access token to the server, receiving the JWT access and refreshing tokens in exchange, and using them to locally perform the login.
IMPORTANT: Don't forget to replace the ---YOUR-APP-ID--- placeholder with your Facebook AppID within the Block #2 source code!

It's plain and simple, isn't it? Well, except for that short, yet rather obscure, piece of code where we execute a function within a given zone. Let's try to understand what we're doing there.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.88.110