Skip to content

Commit

Permalink
added security, CORS, Auth login, exception Handling and Suth tests
Browse files Browse the repository at this point in the history
  • Loading branch information
shreyas957 committed Apr 4, 2024
1 parent 8aadad8 commit 07a8ca7
Show file tree
Hide file tree
Showing 40 changed files with 998 additions and 170 deletions.
4 changes: 2 additions & 2 deletions Dockerrun.aws.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"containerDefinitions": [
{
"name": "shreyas-full-stack-professional-react",
"image": "shreyas957/shreyas-full-stack-professional-react:05.02.2024.15.22.07",
"image": "shreyas957/shreyas-full-stack-professional-react:latest",
"essential": true,
"memory": 256,
"portMappings": [
Expand All @@ -27,7 +27,7 @@
"environment": [
{
"name": "SPRING_DATASOURCE_URL",
"value": "jdbc:postgresql://awseb-e-dxdgfs2cwm-stack-awsebrdsdatabase-ui4am3yu9x47.cm3o7uhddx0b.ap-south-1.rds.amazonaws.com:5432/customer"
"value": "jdbc:postgresql://awseb-e-tqi7h2rkge-stack-awsebrdsdatabase-zcwrzd0atoer.cm3o7uhddx0b.ap-south-1.rds.amazonaws.com:5432/customer"
}
]
}
Expand Down
37 changes: 37 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<docker.username>shreyas957</docker.username>
<docker.image.name>shreyas-full-stack-professional-api</docker.image.name>
<docker.image.tag/>
<jsonwebtoken.version>0.12.5</jsonwebtoken.version>
</properties>

<dependencies>
Expand All @@ -29,6 +30,7 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--suppress VulnerableLibrariesLocal -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down Expand Up @@ -69,6 +71,7 @@


<!-- Test-Containers -->
<!--suppress VulnerableLibrariesLocal -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
Expand All @@ -92,12 +95,46 @@
</dependency>

<!-- WebFlux for spring boot : webTestClient -->
<!--suppress VulnerableLibrariesLocal -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>

<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- For spring security testing -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>

<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jsonwebtoken.version}</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jsonwebtoken.version}</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>${jsonwebtoken.version}</version>
<scope>runtime</scope>
</dependency>

</dependencies>

<build>
Expand Down
5 changes: 4 additions & 1 deletion backend/src/main/java/com/shreyas/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.Random;
import java.util.UUID;

@SpringBootApplication
public class Main {
Expand All @@ -18,7 +20,7 @@ public static void main(String[] args) {
}

@Bean
CommandLineRunner runner(CustomerRepository customerRepository) {
CommandLineRunner runner(CustomerRepository customerRepository, PasswordEncoder passwordEncoder) {

return args -> {
Faker faker = new Faker();
Expand All @@ -31,6 +33,7 @@ CommandLineRunner runner(CustomerRepository customerRepository) {
Customer customer = new Customer(
firstName + " " + lastName,
firstName.toLowerCase() + "." + lastName + "@gmail.com",
passwordEncoder.encode(UUID.randomUUID().toString()),
age,
gender);
customerRepository.save(customer);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.shreyas.auth;

import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api/v1/auth")
public class AuthenticationController {
private final AuthenticationService authenticationService;

public AuthenticationController(AuthenticationService authenticationService) {
this.authenticationService = authenticationService;
}

// With Http post we should not return any payload
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody AuthenticationRequest request) {
AuthenticationResponse authenticationResponse = authenticationService.login(request);

return ResponseEntity.ok()
.header(HttpHeaders.AUTHORIZATION, authenticationResponse.token())
.body(authenticationResponse);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.shreyas.auth;

public record AuthenticationRequest(
String username,
String password
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.shreyas.auth;

import com.shreyas.customer.CustomerDTO;

public record AuthenticationResponse(
String token,
CustomerDTO customerDTO
) {
}
39 changes: 39 additions & 0 deletions backend/src/main/java/com/shreyas/auth/AuthenticationService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.shreyas.auth;

import com.shreyas.customer.Customer;
import com.shreyas.customer.CustomerDTO;
import com.shreyas.customer.CustomerDTOMapper;
import com.shreyas.jwt.JWTUtil;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

@Service
public class AuthenticationService {
private final AuthenticationManager authenticationManager;
private final CustomerDTOMapper customerDTOMapper;
private final JWTUtil jwtUtil;

public AuthenticationService(AuthenticationManager authenticationManager, CustomerDTOMapper customerDTOMapper, JWTUtil jwtUtil) {
this.authenticationManager = authenticationManager;
this.customerDTOMapper = customerDTOMapper;
this.jwtUtil = jwtUtil;
}

//Method which allow customers to login
public AuthenticationResponse login(AuthenticationRequest request) {
Authentication authenticate = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.username(),
request.password()
)
);
Customer principal = (Customer) authenticate.getPrincipal();
CustomerDTO customerDTO = customerDTOMapper.apply(principal);
String token = jwtUtil.issueToken(customerDTO.username(), customerDTO.roles());


return new AuthenticationResponse(token, customerDTO);
}
}
27 changes: 0 additions & 27 deletions backend/src/main/java/com/shreyas/config/WebMvcConfig.java

This file was deleted.

61 changes: 48 additions & 13 deletions backend/src/main/java/com/shreyas/customer/Customer.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package com.shreyas.customer;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import jakarta.persistence.*;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;
import java.util.Objects;

@Entity
Expand All @@ -23,7 +19,7 @@
)
}
)
public class Customer {
public class Customer implements UserDetails {

@Id
@SequenceGenerator(
Expand All @@ -41,6 +37,8 @@ public class Customer {
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private Integer age;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
Expand All @@ -49,17 +47,19 @@ public class Customer {
public Customer() {
}

public Customer(Long id, String name, String email, Integer age, Gender gender) {
public Customer(Long id, String name, String email, String password, Integer age, Gender gender) {
this.id = id;
this.name = name;
this.email = email;
this.password = password;
this.age = age;
this.gender = gender;
}

public Customer(String name, String email, Integer age, Gender gender) {
public Customer(String name, String email, String password, Integer age, Gender gender) {
this.name = name;
this.email = email;
this.password = password;
this.age = age;
this.gender = gender;
}
Expand Down Expand Up @@ -105,6 +105,41 @@ public void setGender(Gender gender) {
this.gender = gender;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority("ROLE_USER"));
}

@Override
public String getPassword() {
return this.password;
}

@Override
public String getUsername() {
return email;
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}

@Override
public String toString() {
return "Customer{" +
Expand Down
28 changes: 15 additions & 13 deletions backend/src/main/java/com/shreyas/customer/CustomerController.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package com.shreyas.customer;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.shreyas.jwt.JWTUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

Expand All @@ -17,30 +12,37 @@
public class CustomerController {

private final CustomerService customerService;
private final JWTUtil jwtUtil;

public CustomerController(CustomerService customerService) {
public CustomerController(CustomerService customerService, JWTUtil jwtUtil) {
this.customerService = customerService;
this.jwtUtil = jwtUtil;
}

// @RequestMapping is same as GetMapping with just only path as shorter version

@RequestMapping(
method = RequestMethod.GET
)
public List<Customer> getCustomers() {
public List<CustomerDTO> getCustomers() {
return customerService.getAllCustomers();
}

@GetMapping("/{customerId}")
public Customer getCustomer(
public CustomerDTO getCustomer(
@PathVariable("customerId") Long customerId) {
return customerService.getCustomer(customerId);
}

@PostMapping
public void registerCustomer(
public ResponseEntity<?> registerCustomer(
@RequestBody CustomerRegistrationRequest request) {
customerService.addCustomer(request);
String jwtToken = jwtUtil.issueToken(request.email(), "ROLE_USER");

return ResponseEntity.ok()
.header(HttpHeaders.AUTHORIZATION, jwtToken)
.build();
}

@DeleteMapping("{customerId}")
Expand Down
Loading

0 comments on commit 07a8ca7

Please sign in to comment.