Skip to content

Commit 425ced4

Browse files
committed
Spring Boot Security,DB Auth and Custom UserService.
1 parent 0de93ee commit 425ced4

14 files changed

+163
-37
lines changed

src/main/java/com/manir/springbootecommercerestapi/config/SecurityConfig.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.manir.springbootecommercerestapi.config;
22

3+
import com.manir.springbootecommercerestapi.security.CustomUserDetailsService;
4+
import org.springframework.beans.factory.annotation.Autowired;
35
import org.springframework.context.annotation.Bean;
46
import org.springframework.context.annotation.Configuration;
57
import org.springframework.http.HttpMethod;
8+
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
69
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
710
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
811
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -14,6 +17,8 @@
1417
import org.springframework.security.crypto.password.PasswordEncoder;
1518
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
1619

20+
import javax.annotation.Resource;
21+
1722
@Configuration
1823
@EnableWebSecurity
1924
/***
@@ -23,6 +28,9 @@
2328
@EnableGlobalMethodSecurity(prePostEnabled = true)
2429
public class SecurityConfig extends WebSecurityConfigurerAdapter {
2530

31+
@Autowired
32+
private CustomUserDetailsService customUserDetailsService;
33+
2634
@Override
2735
protected void configure(HttpSecurity http) throws Exception {
2836
http
@@ -38,13 +46,21 @@ protected void configure(HttpSecurity http) throws Exception {
3846
}
3947

4048
//In memory Auth
41-
@Override
42-
@Bean
43-
protected UserDetailsService userDetailsService() {
44-
UserDetails user = User.builder().username("user").password(passwordEncoder().encode("user")).roles("USER").build();
45-
UserDetails admin = User.builder().username("admin").password(passwordEncoder().encode("admin")).roles("ADMIN").build();
49+
/**
50+
@Override
51+
@Bean
52+
protected UserDetailsService userDetailsService() {
53+
UserDetails user = User.builder().username("customer").password(passwordEncoder().encode("customer")).roles("USER").build();
54+
UserDetails admin = User.builder().username("admin").password(passwordEncoder().encode("admin")).roles("ADMIN").build();
55+
56+
return new InMemoryUserDetailsManager(user, admin);
57+
}
58+
**/
4659

47-
return new InMemoryUserDetailsManager(user, admin);
60+
//DB Auth
61+
@Override
62+
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
63+
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
4864
}
4965

5066
@Bean

src/main/java/com/manir/springbootecommercerestapi/controller/ShoppingCartController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import com.manir.springbootecommercerestapi.dto.CartItemDto;
44
import com.manir.springbootecommercerestapi.response.CartItemResponse;
55
import com.manir.springbootecommercerestapi.service.ShoppingCartService;
6+
import com.manir.springbootecommercerestapi.utils.isAuthenticatedAsAdminOrUser;
67
import org.springframework.http.HttpStatus;
78
import org.springframework.http.ResponseEntity;
9+
import org.springframework.security.access.prepost.PreAuthorize;
810
import org.springframework.web.bind.annotation.*;
911

1012
import javax.annotation.Resource;
@@ -18,6 +20,7 @@ public class ShoppingCartController {
1820
private ShoppingCartService shoppingCartService;
1921

2022
//find by customer api
23+
@isAuthenticatedAsAdminOrUser
2124
@GetMapping("/findByCustomer/{customerId}")
2225
public CartItemResponse findByCustomerId(@PathVariable Long customerId){
2326
CartItemResponse responseCartItems = shoppingCartService.findByCustomerId(customerId);
@@ -26,6 +29,7 @@ public CartItemResponse findByCustomerId(@PathVariable Long customerId){
2629
}
2730

2831
//add item to the cart api
32+
@isAuthenticatedAsAdminOrUser
2933
@PostMapping("/addItem/{customerId}/{productId}/{quantity}")
3034
public ResponseEntity<CartItemResponse> addCartItem(@PathVariable Long customerId,
3135
@PathVariable Long productId,
@@ -36,6 +40,7 @@ public ResponseEntity<CartItemResponse> addCartItem(@PathVariable Long customerI
3640
}
3741

3842
//update item quantity api
43+
@isAuthenticatedAsAdminOrUser
3944
@PutMapping("/updateItemQuantity/{customerId}/{productId}/{quantity}")
4045
public ResponseEntity<CartItemResponse> updateItemQuantity(@PathVariable Long customerId,
4146
@PathVariable Long productId,
@@ -47,6 +52,7 @@ public ResponseEntity<CartItemResponse> updateItemQuantity(@PathVariable Long cu
4752
}
4853

4954
//delete item product api
55+
@isAuthenticatedAsAdminOrUser
5056
@DeleteMapping("/deleteItemProduct/{customerId}/{productId}")
5157
public ResponseEntity<String> deleteItemProduct(@PathVariable Long customerId, @PathVariable Long productId){
5258
shoppingCartService.deleteItemProduct(customerId, productId);

src/main/java/com/manir/springbootecommercerestapi/model/CartItem.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package com.manir.springbootecommercerestapi.model;
22

3-
import com.fasterxml.jackson.annotation.JsonIgnore;
43
import lombok.AllArgsConstructor;
54
import lombok.Data;
65
import lombok.NoArgsConstructor;
76

87
import javax.persistence.*;
9-
import java.util.Set;
108

119
@AllArgsConstructor
1210
@NoArgsConstructor
@@ -27,9 +25,9 @@ public class CartItem {
2725
@JoinColumn(name = "product_id")
2826
private Product product;
2927

30-
//relation with user
28+
//relation with customer
3129
@ManyToOne()
3230
@JoinColumn(name = "customer_id")
33-
private Customer customer;
31+
private User customer;
3432

3533
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.manir.springbootecommercerestapi.model;
2+
3+
import lombok.Data;
4+
5+
import javax.persistence.*;
6+
7+
@Data
8+
@Entity
9+
@Table(name = "roles")
10+
public class Role {
11+
12+
@Id
13+
@GeneratedValue(strategy = GenerationType.IDENTITY)
14+
private Long id;
15+
@Column(length = 60)
16+
private String name;
17+
}

src/main/java/com/manir/springbootecommercerestapi/model/Customer.java renamed to src/main/java/com/manir/springbootecommercerestapi/model/User.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package com.manir.springbootecommercerestapi.model;
22

3-
import com.fasterxml.jackson.annotation.JsonIgnore;
43
import lombok.Data;
54

65
import javax.persistence.*;
76
import java.util.Set;
87

98
@Data
109
@Entity
11-
@Table(name = "customers", uniqueConstraints = {@UniqueConstraint(columnNames = {"userName"}),
10+
@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = {"userName"}),
1211
@UniqueConstraint(columnNames = {"email"})
1312
})
14-
public class Customer {
13+
public class User {
1514
@Id
1615
@GeneratedValue(strategy = GenerationType.IDENTITY)
1716
private Long id;
@@ -25,4 +24,11 @@ public class Customer {
2524
fetch = FetchType.LAZY, orphanRemoval = true,
2625
mappedBy = "customer")
2726
private Set<CartItem> cartItems;
28-
}
27+
28+
//relation with role
29+
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
30+
@JoinTable(name = "user_roles",
31+
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
32+
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
33+
private Set<Role> roles;
34+
}

src/main/java/com/manir/springbootecommercerestapi/repository/CartItemRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public interface CartItemRepository extends JpaRepository<CartItem, Long> {
1111

1212
List<CartItem> findByCustomerId(Long customerId);
1313

14-
//CartItem findByCustomerAndProduct(Customer customer, Product product);
14+
//CartItem findByCustomerAndProduct(User customer, Product product);
1515
CartItem findByCustomerIdAndProductId(Long customerId, Long productId);
1616

1717
@Query("UPDATE CartItem c SET c.quantity = ?3 WHERE c.product.id = ?2 AND c.customer.id = ?1")

src/main/java/com/manir/springbootecommercerestapi/repository/CustomerRepository.java

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.manir.springbootecommercerestapi.repository;
2+
3+
import com.manir.springbootecommercerestapi.model.Role;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Optional;
7+
8+
public interface RoleRepository extends JpaRepository<Role, Long> {
9+
Optional<Role> findByName(String name);
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.manir.springbootecommercerestapi.repository;
2+
3+
import com.manir.springbootecommercerestapi.model.User;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Optional;
7+
8+
public interface UserRepository extends JpaRepository<User, Long>{
9+
10+
Optional<User> findByEmail(String email);
11+
Optional<User> findByUserNameOrEmail(String username, String email);
12+
Optional<User> findByUserName(String username);
13+
Boolean existsByUserName(String username);
14+
Boolean existsByEmail(String email);
15+
16+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.manir.springbootecommercerestapi.security;
2+
3+
import com.manir.springbootecommercerestapi.model.Role;
4+
import com.manir.springbootecommercerestapi.model.User;
5+
import com.manir.springbootecommercerestapi.repository.UserRepository;
6+
import lombok.AllArgsConstructor;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.security.core.GrantedAuthority;
9+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
10+
import org.springframework.security.core.userdetails.UserDetails;
11+
import org.springframework.security.core.userdetails.UserDetailsService;
12+
import org.springframework.security.core.userdetails.UsernameNotFoundException;
13+
import org.springframework.stereotype.Service;
14+
15+
import javax.annotation.Resource;
16+
import java.util.Collection;
17+
import java.util.Set;
18+
import java.util.stream.Collectors;
19+
20+
@Service
21+
@AllArgsConstructor
22+
public class CustomUserDetailsService implements UserDetailsService {
23+
private final UserRepository userRepository;
24+
25+
@Override
26+
public UserDetails loadUserByUsername(String userNameOrEmail) throws UsernameNotFoundException {
27+
User user = userRepository.findByUserNameOrEmail(userNameOrEmail, userNameOrEmail)
28+
.orElseThrow(
29+
() -> new UsernameNotFoundException("User not found with username or email: " + userNameOrEmail)
30+
);
31+
return new org.springframework.security.core.userdetails.User(
32+
user.getEmail(),
33+
user.getPassword(),
34+
mapRolesToAuthorities(user.getRoles())
35+
);
36+
}
37+
38+
private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Set<Role> roles){
39+
return roles.stream()
40+
.map(role -> new SimpleGrantedAuthority(role.getName()))
41+
.collect(Collectors.toList());
42+
}
43+
}

src/main/java/com/manir/springbootecommercerestapi/service/Impl/ShoppingCartServiceImpl.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
import com.manir.springbootecommercerestapi.exception.EcommerceApiException;
55
import com.manir.springbootecommercerestapi.exception.ResourceNotFoundException;
66
import com.manir.springbootecommercerestapi.model.CartItem;
7-
import com.manir.springbootecommercerestapi.model.Customer;
7+
import com.manir.springbootecommercerestapi.model.User;
88
import com.manir.springbootecommercerestapi.model.Product;
99
import com.manir.springbootecommercerestapi.repository.CartItemRepository;
10-
import com.manir.springbootecommercerestapi.repository.CustomerRepository;
10+
import com.manir.springbootecommercerestapi.repository.UserRepository;
1111
import com.manir.springbootecommercerestapi.repository.ProductRepository;
1212
import com.manir.springbootecommercerestapi.response.CartItemResponse;
1313
import com.manir.springbootecommercerestapi.service.CommonService;
@@ -19,7 +19,6 @@
1919

2020
import javax.annotation.Resource;
2121
import javax.transaction.Transactional;
22-
import java.util.ArrayList;
2322
import java.util.List;
2423
import java.util.stream.Collectors;
2524
import java.util.stream.DoubleStream;
@@ -35,7 +34,7 @@ public class ShoppingCartServiceImpl implements ShoppingCartService {
3534
@Resource
3635
private ProductRepository productRepository;
3736
@Resource
38-
private CustomerRepository customerRepository;
37+
private UserRepository userRepository;
3938
@Resource
4039
private CommonService commonService;
4140
@Override
@@ -44,7 +43,7 @@ public CartItemResponse findByCustomerId(Long customerId) {
4443
List<CartItem> cartItems = cartItemRepository.findByCustomerId(customerId);
4544

4645
if (cartItems.size() == 0){
47-
throw new EcommerceApiException("Customer has no product in cart item", HttpStatus.BAD_REQUEST);
46+
throw new EcommerceApiException("User has no product in cart item", HttpStatus.BAD_REQUEST);
4847
}
4948

5049
List<CartItemDto> cartItemDtoList = cartItems.stream()
@@ -61,7 +60,7 @@ public CartItemResponse findByCustomerId(Long customerId) {
6160
@Override
6261
public CartItemResponse addCartItem(Long customerId, Long productId, Integer quantity) {
6362
Integer addedQuantity = quantity;
64-
Customer customer = findCustomerById(customerId);
63+
User user = findCustomerById(customerId);
6564
Product product = findProductById(productId);
6665

6766
CartItem cartItem = cartItemRepository.findByCustomerIdAndProductId(customerId, productId);
@@ -70,7 +69,7 @@ public CartItemResponse addCartItem(Long customerId, Long productId, Integer qua
7069
cartItem.setQuantity(addedQuantity);
7170
}else {
7271
cartItem = new CartItem();
73-
cartItem.setCustomer(customer);
72+
cartItem.setCustomer(user);
7473
cartItem.setProduct(product);
7574
cartItem.setQuantity(quantity);
7675
}
@@ -120,12 +119,12 @@ private CartItem mapToEntity(CartItemDto cartItemDto){
120119
return cartItem;
121120
}
122121

123-
private Customer findCustomerById(Long customerId){
124-
Customer customer = customerRepository.findById(customerId)
122+
private User findCustomerById(Long customerId){
123+
User user = userRepository.findById(customerId)
125124
.orElseThrow(
126-
() -> new ResourceNotFoundException("Customer", customerId)
125+
() -> new ResourceNotFoundException("User", customerId)
127126
);
128-
return customer;
127+
return user;
129128
}
130129

131130
private Product findProductById(Long productId){
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.manir.springbootecommercerestapi.utils;
2+
3+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
4+
import org.springframework.security.crypto.password.PasswordEncoder;
5+
6+
public class PasswordEncoderGenerator {
7+
public static void main(String[] args) {
8+
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
9+
System.out.println("ADMIN: " + passwordEncoder.encode("admin"));
10+
System.out.println("USER: " + passwordEncoder.encode("user"));
11+
}
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.manir.springbootecommercerestapi.utils;
2+
3+
import org.springframework.security.access.prepost.PreAuthorize;
4+
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@PreAuthorize("hasRole('ADMIN') || hasRole('USER')")
10+
public @interface isAuthenticatedAsAdminOrUser {
11+
}

src/main/resources/application.properties

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ spring.jpa.hibernate.ddl-auto=update
99
#TO see security is working on the console
1010
logging.level.org.springframework.security=DEBUG
1111
#Spring security default auth credential
12-
#spring.security.user.password= user
13-
#spring.security.user.name= user
14-
#spring.security.user.roles= ADMIN
12+
#spring.security.customer.password= customer
13+
#spring.security.customer.name= customer
14+
#spring.security.customer.roles= ADMIN
1515

0 commit comments

Comments
 (0)