I'm trying to learn how to secure a basic angular app. I'm working with springboot back office with basicauth. And I've implemented HTTP_INTERCEPTOR.
I've followed this guides:
- https://www.baeldung.com/spring-boot-angular-web
- https://www.javaguides.net/2019/04/spring-boot-spring-security-angular-example-tutorial.html
My code works fine but only 1 time. Just call the form login and perform it, redirect and everything appears in my front office with status code 200.
But if i hit the refresh button, my API answer with status code 401. I've added a console log message in my condition in HttpInterceptorService to test if user are connected and this one appear in console so i think it's just header who are not applied.
I've looked up if i've import multiple HttpClientModule, but only one in my app.module.ts
Here's some code:
AppModule
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { ProductServiceService } from './service/product-service.service';
import { HttpInterceptorServiceService } from './login/http-interceptor-service.service';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ProductListComponent } from './product-list/product-list.component';
import { LoginComponent } from './login/login.component';
import { ProductHomeComponent } from './product-home/product-home.component';
@NgModule({
declarations: [
AppComponent,
ProductListComponent,
LoginComponent,
ProductHomeComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HttpInterceptorServiceService,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
http-interceptor-service.service.ts
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable()
export class HttpInterceptorServiceService implements HttpInterceptor {
constructor(private authService: AuthService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.authService.isUserLoggedIn() && req.url.indexOf('basicauth') === -1) {
console.log("User is logged");
const authReq = req.clone({
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': `Basic ${window.btoa(this.authService.username + ":" + this.authService.password)}`
})
});
return next.handle(authReq);
} else {
return next.handle(req);
}
}
}
auth.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class AuthService {
// BASE_PATH: 'http://localhost:8080'
USER_NAME_SESSION_ATTRIBUTE_NAME = 'authenticatedUser'
public username: String;
public password: String;
constructor(private http: HttpClient) {
}
authService(username: String, password: String) {
return this.http.get(`http://localhost:8080/basicauth`,
{ headers: { authorization: this.createBasicAuthToken(username, password) } }).pipe(map((res) => {
this.username = username;
this.password = password;
this.registerSuccessfulLogin(username, password);
}));
}
createBasicAuthToken(username: String, password: String) {
return 'Basic ' + window.btoa(username + ":" + password)
}
registerSuccessfulLogin(username, password) {
sessionStorage.setItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME, username)
}
logout() {
sessionStorage.removeItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME);
this.username = null;
this.password = null;
}
isUserLoggedIn() {
let user = sessionStorage.getItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME)
if (user === null) return false
return true
}
getLoggedInUserName() {
let user = sessionStorage.getItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME)
if (user === null) return ''
return user
}
}
login.component.ts
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { AuthService } from './auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
username: string;
password : string;
errorMessage = 'Invalid Credentials';
successMessage: string;
invalidLogin = false;
loginSuccess = false;
constructor(
private route: ActivatedRoute,
private router: Router,
private authService: AuthService) { }
ngOnInit() {
}
handleLogin() {
this.authService.authService(this.username, this.password).subscribe((result)=> {
this.invalidLogin = false;
this.loginSuccess = true;
this.successMessage = 'Login Successful.';
this.router.navigate(['/products']);
}, () => {
this.invalidLogin = true;
this.loginSuccess = false;
});
}
}
You should save the information you have saved in the localStorage or sessionStorage or anywhere else after refreshing it so that you do not have any problems. My suggestion is to do this in the app.component.ts , such as the link and sample code below.
I have done the same thing once before. link
I hope this information helps you solve your problem.