The problem basically is that when I'm logged into the dashboard, every time I reload the browser page it renders the login component for an instant
TokenService
export class TokenService {
isAuthentications: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
constructor(@Inject(PLATFORM_ID) private platformId: Object) {
const token = this.getToken();
if(token){
this.updateToken(true)
}
}
setToken(token: string){
this.updateToken(true);
localStorage.setItem('user', token)
}
updateToken(status: boolean){
this.isAuthentications.next(status)
}
getToken(): string | null{
if (typeof window !== 'undefined' && window.sessionStorage) {
return localStorage.getItem('user');
}
return null
}
}
AuthGuard
export const authGuard: CanActivateFn = (route, state) =\> {
const tokenService = inject(TokenService)
const router = inject(Router)
// tokenService.isAuthentications.subscribe({
// next: (v) =\> {
// if(!v){
// router.navigate(['/login'])
// }
// }
// })
// return true;
return tokenService.isAuthentications.pipe(map( (user) =\> {
if(!user){
return router.createUrlTree(['/login']);
}else{
return true
}
}))
};
Routes
export const routes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: '', redirectTo: 'login', pathMatch: 'full'},
{path: '' , component: LayoutComponent, children: [
{path: 'dashboard', component: DashboardComponent, canActivate: [authGuard] }
]}
];
I've tried other other approaches on how to secure the route however, whenever my guard should redirect to 'login' it has this behavior
The issue is due to enabling SSR, since there is no window
or localStorage
on the server. The login page is getting generated on the server and when sent to frontend. Just before the UI is run again (hydration I guess!), we see a flash of the login page.
To solve this issue, all you need to do is to make the login page show nothing when it's generated on the server, then it gives the impression that the app is loading. Alternatively you could also show the splash screen with a loader on the login page, when the mode is server, this will get rid of this bug.
...
export class LoginComponent {
isUser = signal(false)
isServer = false;
constructor(private auth: AuthService, private router: Router, private tokenService: TokenService,
@Inject(PLATFORM_ID) platformId: Object){
this.isServer = isPlatformServer(platformId);
console.log('aqui')
const userToken = this.tokenService.getToken()
if(userToken){
this.isUser.set(true)
}
}
...
@if (!this.isUser() && !isServer) {
<p>login works!</p>
<button mat-raised-button (click)="login()"> LOGIN </button>
}
HTML
@if(isServer) {
<div style="height:100vh;width:100vw;background-color: rgb(194, 24, 91); display: flex; align-items: center; justify-content: center;">
<div id="loading"></div>
</div>
} @else {
@if (!this.isUser()) {
<p>login works!</p>
<button mat-raised-button (click)="login()"> LOGIN </button>
}
}
CSS
#loading {
display: inline-block;
width: 50px;
height: 50px;
border: 3px solid rgba(255,255,255,.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s ease-in-out infinite;
-webkit-animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { -webkit-transform: rotate(360deg); }
}
@-webkit-keyframes spin {
to { -webkit-transform: rotate(360deg); }
}
export class LoginComponent {
isServer = false;
isUser = signal(false)
constructor(
private auth: AuthService,
private router: Router,
private tokenService: TokenService,
@Inject(PLATFORM_ID) platformId: Object){
this.isServer = isPlatformServer(platformId);
console.log('aqui')
const userToken = this.tokenService.getToken()
if(userToken){
this.isUser.set(true)
}
}