spring boot angular security 20 Jan 21
spring boot angular security 20 Jan 21
==============
Agenda:
=> spring boot rest
=> spring boot angular 8
=> spring boot angular 8 security
server.servlet.context-path=/empapp
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/kr_jdbc?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=create
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
spring.jpa.show-sql=true
@Repository
public interface EmpRepo extends CrudRepository<Employee, Integer>{
@Service
@Transactional
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmpRepo empRepo;
@Override
public List<Employee> getAll() {
return (List<Employee>) empRepo.findAll();
}
@Override
public Employee getEmployeeById(int id) {
return empRepo.findById(id).orElseThrow(EmployeeNotFoundException::
new);
}
@Override
public Employee save(Employee emp) {
return empRepo.save(emp);
}
@Override
public Employee delete(int empId) {
Employee employeeToDelete=getEmployeeById(empId);
empRepo.delete(employeeToDelete);
return employeeToDelete;
}
@Override
public Employee update(int empId, Employee emp) {
Employee employeeToUpdate=getEmployeeById(empId);
employeeToUpdate.setName(emp.getName());
employeeToUpdate.setAge(emp.getAge());
return empRepo.save(employeeToUpdate);
}
}
@Autowired
private EmployeeService employeeService;
@GetMapping(path="employee", produces=MediaType.APPLICATION_JSON_VALUE)
public List<Employee> allEmployees(){
return employeeService.getAll();
}
@GetMapping(path="employee/{id}",produces=MediaType.APPLICATION_JSON_VALUE )
public Employee getEmployeeById(@PathVariable(name="id")int id){
return employeeService.getEmployeeById(id);
}
@PostMapping(path="employee",produces=MediaType.APPLICATION_JSON_VALUE,
consumes=MediaType.APPLICATION_JSON_VALUE )
public Employee addEmployee(@RequestBody Employee employee){
return employeeService.save(employee);
}
@PutMapping(path="employee/{id}",produces=MediaType.APPLICATION_JSON_VALUE,
consumes=MediaType.APPLICATION_JSON_VALUE )
public Employee updateEmployee(@PathVariable(name="id") int id,
@RequestBody Employee emp){
return employeeService.update(id, emp);
@DeleteMapping(path="employee/{id}",produces=MediaType.APPLICATION_JSON_VALUE)
public Employee deleteEmplloyee(@PathVariable(name="id") int id){
return employeeService.delete(id);
}
}
@SpringBootApplication
public class DemoApplication implements CommandLineRunner{
@Autowired
private EmployeeService empService;
or
@Component
public class CORSFilter implements Filter {
1. configure bootstrap:
install bootstrap:
----------------
sudo npm install bootstrap --save
@import "~bootstrap/dist/css/bootstrap.min.css"
check if working:
------------------
<router-outlet></router-outlet>
alternative ways:
----------------
angular.json:
------------
"styles": [
"./node_modules/bootstrap/dist/css/bootstrap-grid.css",
"src/styles.css"
],
angular.cli.json
---------------------
"../node_modules/bootstrap/dist/css/bootstrap.min.css"
"../node_modules/jquery/dist/jquery.min.js",
"../node_modules/bootstrap/dist/js/bootstrap.min.js"
employees: Employee[];
constructor() { }
ngOnInit() {
this.employees=[
{
"id":1,
"name":"rajeev",
"age":40
},
{
"id":2,
"name":"ekta",
"age":40
},
{
"id":3,
"name":"gunika",
"age":15
}
];
}
<div class="text-center">
<app-employee></app-employee>
</div>
ng g s employee
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
install rxjs:
--------------
employee service:
--------------------
http://localhost:8080/empapp/api/employee
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
private baseURL="http://localhost:8080/empapp/employee";
constructor(private httpClient: HttpClient) { }
getEmployeesList(): Observable<Employee[]>{
return this.httpClient.get<Employee[]>(`${this.baseURL}`);
}
}
employee component:
--------------------
@Component({
selector: 'app-employee',
templateUrl: './employee.component.html',
styleUrls: ['./employee.component.css']
})
export class EmployeeComponent implements OnInit {
employees: Employee[];
ngOnInit() {
this.getEmployees();
}
private getEmployees(){
this.employeeService.getEmployeesList().subscribe(data=>{
this.employees=data;
});
}
<div class="text-center">
<router-outlet></router-outlet>
</div>
Routing and Navigation:
-------------------------
add to app.component.html:
--------------------------
<div class="text-center">
<router-outlet></router-outlet>
</div>
add to style.css
------------------
@import "~bootstrap/dist/css/bootstrap.min.css";
.footer {
position: absolute;
bottom: 0;
width:100%;
height: 40px;
background-color: blue;
text-align: center;
color: white;
}
update app.component.html
------------------------
ngOnInit() {
}
onSubmit(){
console.log(this.employee);
}
}
<div class="form-group">
<label> Name</label>
<input type="text" class ="form-control" id = "name"
[(ngModel)] = "employee.name" name = "name">
</div>
<div class="form-group">
<label> Age </label>
<input type="text" class ="form-control" id = "age"
[(ngModel)] = "employee.age" name = "age">
</div>
</form>
</div>
Note:
=> Error:Can't bind to 'ngModel' since it isn't a known property of 'input'.
(
imports: [
BrowserModule,
FormsModule
]
@Component({
selector: 'app-create-employee',
templateUrl: './create-employee.component.html',
styleUrls: ['./create-employee.component.css']
})
saveEmployee(){
this.employeeService.createEmployee(this.employee).subscribe( data =>{
console.log(data);
this.goToEmployeeList();
},
error => console.log(error));
}
goToEmployeeList(){
this.router.navigate(['/employees']);
}
onSubmit(){
console.log(this.employee);
this.saveEmployee();
}
}
ng g c update-employee
];
employees: Employee[];
ngOnInit() {
this.getEmployees();
}
private getEmployees(){
this.employeeService.getEmployeesList().subscribe(data=>{
this.employees=data;
});
}
updateEmployee(id: number){
console.log(`-----------`)
this.router.navigate(['update-employee', id]);
}
ngOnInit(): void {
this.id=this.route.snapshot.params['id'];
this.employeeService.getEmployeeById(this.id).subscribe(data=>{
this.employee=data;
}, error=>console.log(error))
}
Now code for update and route back to showing all records:
----------------------------------------------------------
@Component({
selector: 'app-update-employee',
templateUrl: './update-employee.component.html',
styleUrls: ['./update-employee.component.css']
})
ngOnInit(): void {
this.id=this.route.snapshot.params['id'];
this.employeeService.getEmployeeById(this.id).subscribe(data=>{
this.employee=data;
}, error=>console.log(error))
}
onSubmit(){
this.employeeService.updateEmployee(this.id, this.employee)
.subscribe(data=> {
this.goToEmployeeList();
}, error=> console.log(error))
}
goToEmployeeList(){
this.router.navigate(['/employees']);
}
}
Delete employee:
-------------------
//...........
deleteEmployee(id: number): Observable<Object>{
return this.httpClient.delete(`${this.baseURL}/${id}`);
}
}
//....
deleteEmployee(id: number){
this.employeeService.deleteEmployee(id).subscribe(data=>{
this.getEmployees();
console.log(data);
})
}
employeeDetails(id: number){
this.router.navigate(['employee-details', id]);
}
}
ng g c employee-details
];
EmployeeDetailsComponent code:
--------------------------------
import { ActivatedRoute, Router } from '@angular/router';
import { Employee } from '../employee';
import { EmployeeService } from '../employee.service';
id: number
employee: Employee=new Employee();
ngOnInit(): void {
this.id = this.route.snapshot.params['id'];
employeeDetails(id: number){
this.router.navigate(['employee-details', id]);
}
}
Employee service:
---------------
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
getEmployeesList(): Observable<Employee[]>{
return this.httpClient.get<Employee[]>(`${this.baseURL}`);
}
step 1:
Create authentication service:
-------------------------------
=> Create a new authentication service where we check if the user name and
password is
correct then set it in session storage.
ng g s authentication
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
constructor() { }
authenticate(username, password) {
if (username === "raj" && password === "raj123") {
sessionStorage.setItem('username', username)
return true;
} else {
return false;
}
}
isUserLoggedIn() {
let user = sessionStorage.getItem('username')
console.log(!(user === null))
return !(user === null)
}
logOut() {
sessionStorage.removeItem('username')
}
}
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
username = 'raj'
password = ''
invalidLogin = false
ngOnInit() {
}
checkLogin() {
if (this.loginservice.authenticate(this.username, this.password)) {
this.router.navigate([''])
this.invalidLogin = false
} else
this.invalidLogin = true
}
}
from:
--------
<div class="container">
<div>
User Name : <input type="text" name="username" [(ngModel)]="username">
Password : <input type="password" name="password" [(ngModel)]="password">
</div>
<button (click)=checkLogin() class="btn btn-success">
Login
</button>
</div>
Add the login path to the routing module.
-----------------------------
@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.css']
})
export class LogoutComponent implements OnInit {
constructor(
private authentocationService: AuthenticationService,
private router: Router) {
ngOnInit() {
this.authentocationService.logOut();
this.router.navigate(['login']);
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
constructor(private loginService:AuthenticationService) { }
title = 'empclient';
ngOnInit() {
}
}
=> So we should first check if the user is logged in and only then allow the
user to view the page. We achive this using the CanActivate
interface.
this.router.navigate(['login']);
return false;
}
}
Modify the app.routing.ts to activate route only if the user is logged in using the
above AuthGaurdService.
-----------------------------------------------------------------------------------
---------
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().
authorizeRequests().antMatchers(HttpMethod.OPTIONS,
"/**").permitAll().anyRequest().authenticated()
.and().httpBasic();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws
Exception {
auth.inMemoryAuthentication().withUser("raj").password("{noop}raj123").roles("USER"
);
}
}
@GetMapping(produces = "application/json")
@RequestMapping({ "/validateLogin" })
public AuthResponse validateLogin() {
return new AuthResponse("User successfully authenticated");
}
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
private baseURL="http://localhost:8080/empapp/employee";
constructor(private httpClient: HttpClient) { }
getEmployeesList(): Observable<Employee[]>{
let username='raj'
let password='raj123'
const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(username + ':'
+ password) });
return this.httpClient.get<Employee[]>(`${this.baseURL}`,{headers});
}
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
constructor(private httpClient:HttpClient) { }
authenticate(username, password) {
const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(username + ':'
+ password) });
return
this.httpClient.get<AuthResponse>('http://localhost:8080/empapp/validateLogin',
{headers}).pipe(
map(
userData => {
sessionStorage.setItem('username',username);
return userData;
}
)
);
}
isUserLoggedIn() {
let user = sessionStorage.getItem('username')
console.log(!(user === null))
return !(user === null)
}
logOut() {
sessionStorage.removeItem('username')
}
}
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
username = ''
password = ''
invalidLogin = false
ngOnInit() {
}
checkLogin() {
(this.loginservice.authenticate(this.username, this.password).subscribe(
data => {
this.router.navigate([''])
this.invalidLogin = false
},
error => {
this.invalidLogin = true
}
)
);
We had seen we had to duplicate the code for adding Basic Auth
Headers to the HTTPRequest before making HTTP calls.
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
constructor(private httpClient:HttpClient) { }
authenticate(username, password) {
const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(username + ':'
+ password) });
return
this.httpClient.get<AuthResponse>('http://localhost:8080/empapp/validateLogin',
{headers}).pipe(
map(
userData => {
sessionStorage.setItem('username', username);
let authString = 'Basic ' + btoa(username + ':' + password);
sessionStorage.setItem('basicauth', authString);
return userData;
}
)
);
}
isUserLoggedIn() {
let user = sessionStorage.getItem('username')
console.log(!(user === null))
return !(user === null)
}
logOut() {
sessionStorage.removeItem('username')
}
}
HttpInterceptor service:
------------------------
ng g service BasicAuthHtppInterceptor
@Injectable({
providedIn: 'root'
})
export class BasicAuthHtppInterceptorService implements HttpInterceptor {
constructor() { }
return next.handle(req);
}
}
providers: [
{
provide:HTTP_INTERCEPTORS, useClass:BasicAuthHtppInterceptorService,
multi:true
}
]
Finally we will remove the hardcoded basic auth logic from the Http client service.
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
private baseURL="http://localhost:8080/empapp/employee";
constructor(private httpClient: HttpClient) { }
getEmployeesList(): Observable<Employee[]>{
// let username='raj'
// let password='raj123'
// const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(username +
':' + password) });
// return this.httpClient.get<Employee[]>(`${this.baseURL}`,{headers});
return this.httpClient.get<Employee[]>(`${this.baseURL}`);
}