I downloaded universal-starter for nodejs and started migrating my website from old angular-rc4. But when I have to implement authentication (in my case it's JWT which is stored in localStorage), the server dont have localStorage and cookie so that angular is rendered only on client.
I've follow this guide: https://github.com/angular/universal-starter/issues/148 but it didnt work.
Below is my code:
authentication.services.ts
import { OpaqueToken } from '@angular/core';
export let AUTH_SERVICES = new OpaqueToken('auth.services');
export interface AuthenticationService {
forgotPassword(email: any);
isAuthenticated();
getCurrentUser();
refreshToken();
signin(user : any);
signout();
signup(user : any);
}
server.authentication.ts
import { Injectable } from '@angular/core';
import { AuthenticationService } from './authentication.services';
@Injectable()
export class ServerAuthenticationService implements AuthenticationService {
forgotPassword(email: any) {
throw new Error('Forgot password cannot be called while doing server side rendering');
}
isAuthenticated() {
return false;
}
getCurrentUser(){
if(this.isAuthenticated()) {
return {};
}
return {};
}
refreshToken() {
}
signin(user : any) {
throw new Error('Login cannot be called while doing server side rendering');
}
signout() {
throw new Error('Logout cannot be called while doing server side rendering');
}
signup(user : any) {
throw new Error('Sign up cannot be called while doing server side rendering');
}
}
clientAuthentication.services.ts
@Injectable()
export class UserService implements AuthenticationService {
forgotPassword(email: any){
// client implementation
}
isAuthenticated() {
// client implementation
}
getCurrentUser() {
// client implementation
}
refreshToken() {
// client implementation
}
signin(user : any){
// client implementation
}
signout(){
// client implementation
}
signup(user : any) {
// client implementation
}
}
app.browser.module.ts
@NgModule({
bootstrap: [ AppComponent ],
declarations: [ AppComponent ],
imports: [
UniversalModule, // BrowserModule, HttpModule, and JsonpModule are included
FormsModule,
SharedModule,
HomeModule,
AboutModule,
NavbarModule,
AppRoutingModule
],
providers: [
{ provide: 'isBrowser', useValue: isBrowser },
{ provide: 'isNode', useValue: isNode },
{ provide: 'LRU', useFactory: getLRU, deps: [] },
{ provide: AUTH_SERVICES, useFactory: UserService},
CacheService
]
})
app.node.module.ts
@NgModule({
bootstrap: [ AppComponent ],
declarations: [ AppComponent ],
imports: [
UniversalModule, // NodeModule, NodeHttpModule, and NodeJsonpModule are included
FormsModule,
SharedModule,
HomeModule,
AboutModule,
NavbarModule,
AppRoutingModule
],
providers: [
{ provide: 'isBrowser', useValue: isBrowser },
{ provide: 'isNode', useValue: isNode },
{
provide: 'LRU',
useFactory: getLRU,
deps: [
[new Inject('LRU'), new Optional(), new SkipSelf()]
]
},
{ provide: AUTH_SERVICES, useFactory: ServerAuthenticationService },
CacheService
]
})
Then how to have the same page output while navigating to that page on the client via a router transition vs on the server via a browser refresh?
Thanks in advance
In node you can use the request and response properties in your express application and inject them in your angular application based on server on browser module. request.cookies holds an objects that maps KVPS as to your cookies.
For some (outdated) examples on this please look here and here: https://github.com/angular/universal-starter/blob/master/src/node.module.ts#L43 https://github.com/angular/universal-starter/blob/master/src/browser.module.ts#L52
The code might get outdated soon, but the principle holds. Use dependency injection to inject the request on the server in your app and some stub for the request ( that might still expose the browser cookies ) in the version for the browser.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With