diff --git a/shopping-cart-backend/pom.xml b/shopping-cart-backend/pom.xml
index 9a50ce9..069f296 100644
--- a/shopping-cart-backend/pom.xml
+++ b/shopping-cart-backend/pom.xml
@@ -34,13 +34,12 @@
org.springframework.boot
- spring-boot-starter-test
- test
+ spring-boot-starter-data-jpa
org.springframework.boot
- spring-boot-starter-data-jpa
- ${spring-boot.version}
+ spring-boot-starter-test
+ test
org.springframework.security
diff --git a/shopping-cart-backend/shopping-cart.iml b/shopping-cart-backend/shopping-cart.iml
index 1a6d61b..8054dec 100644
--- a/shopping-cart-backend/shopping-cart.iml
+++ b/shopping-cart-backend/shopping-cart.iml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/ShoppingCartApplication.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/Main.java
similarity index 69%
rename from shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/ShoppingCartApplication.java
rename to shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/Main.java
index fe346c6..76f346c 100644
--- a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/ShoppingCartApplication.java
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/Main.java
@@ -4,10 +4,10 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
-public class ShoppingCartApplication {
+public class Main {
public static void main(String[] args) {
- SpringApplication.run(ShoppingCartApplication.class, args);
+ SpringApplication.run(Main.class, args);
}
}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/config/PasswordEncoderConfig.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/config/PasswordEncoderConfig.java
new file mode 100644
index 0000000..63fed92
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/config/PasswordEncoderConfig.java
@@ -0,0 +1,13 @@
+package fptu.swp391.shoppingcart.authentication.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+@Configuration
+public class PasswordEncoderConfig {
+ @Bean
+ public BCryptPasswordEncoder bCryptPasswordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/config/SecurityConfig.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/config/SecurityConfig.java
new file mode 100644
index 0000000..826260f
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/config/SecurityConfig.java
@@ -0,0 +1,32 @@
+package fptu.swp391.shoppingcart.authentication.config;
+
+import fptu.swp391.shoppingcart.authentication.service.AuthenticationProviderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+ @Autowired
+ private AuthenticationProviderService authenticationProvider;
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) {
+ auth.authenticationProvider(authenticationProvider);
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ //@formatter:off
+ http
+ .csrf().disable()
+ .authorizeRequests()
+ .mvcMatchers("/login").permitAll()
+ .anyRequest().authenticated()
+ .and().httpBasic();
+// .and().formLogin();
+ //@formatter:on
+ }
+}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/Authority.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/Authority.java
new file mode 100644
index 0000000..af92d8d
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/Authority.java
@@ -0,0 +1,17 @@
+package fptu.swp391.shoppingcart.authentication.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+@Entity
+@Getter
+@Setter
+@Table(name = "AUTHORITY")
+public class Authority extends BaseEntity {
+ @Column(name = "NAME", nullable = false, length = 50)
+ private String name;
+}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/BaseEntity.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/BaseEntity.java
new file mode 100644
index 0000000..d4486bb
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/BaseEntity.java
@@ -0,0 +1,21 @@
+package fptu.swp391.shoppingcart.authentication.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.*;
+
+@Getter
+@Setter
+@MappedSuperclass
+public abstract class BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "ID", nullable = false)
+ private Long id;
+
+ @Version
+ @Column(name = "VERSION", nullable = false)
+ private int version;
+}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/UserEntity.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/UserEntity.java
new file mode 100644
index 0000000..449f3e1
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/entity/UserEntity.java
@@ -0,0 +1,49 @@
+package fptu.swp391.shoppingcart.authentication.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+
+@Entity
+@Getter
+@Setter
+@Table(name = "USER")
+public class UserEntity extends BaseEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Column(name = "USERNAME", nullable = false, unique = true)
+ private String username;
+
+ @Column(name = "PASSWORD", nullable = false)
+ private String password;
+
+ @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
+ @JoinColumn(name = "USER_ID")
+ private Set authorities = new LinkedHashSet<>();
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ UserEntity that = (UserEntity) o;
+
+ if (!username.equals(that.username)) return false;
+ if (!password.equals(that.password)) return false;
+ return Objects.equals(authorities, that.authorities);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = username.hashCode();
+ result = 31 * result + password.hashCode();
+ result = 31 * result + (authorities != null ? authorities.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/model/CustomUserDetails.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/model/CustomUserDetails.java
new file mode 100644
index 0000000..c571392
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/model/CustomUserDetails.java
@@ -0,0 +1,55 @@
+package fptu.swp391.shoppingcart.authentication.model;
+
+import fptu.swp391.shoppingcart.authentication.entity.UserEntity;
+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.stream.Collectors;
+
+public class CustomUserDetails implements UserDetails{
+
+ private final UserEntity user;
+
+ public CustomUserDetails(UserEntity user) {
+ this.user = user;
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return user.getAuthorities().stream()
+ .map(a -> new SimpleGrantedAuthority(a.getName()))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public String getPassword() {
+ return user.getPassword();
+ }
+
+ @Override
+ public String getUsername() {
+ return user.getUsername();
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/repository/UserRepository.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/repository/UserRepository.java
new file mode 100644
index 0000000..8dcdfdf
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/repository/UserRepository.java
@@ -0,0 +1,10 @@
+package fptu.swp391.shoppingcart.authentication.repository;
+
+import fptu.swp391.shoppingcart.authentication.entity.UserEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface UserRepository extends JpaRepository {
+ Optional findUserByUsername(String username);
+}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/service/AuthenticationProviderService.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/service/AuthenticationProviderService.java
new file mode 100644
index 0000000..b4b397d
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/service/AuthenticationProviderService.java
@@ -0,0 +1,39 @@
+package fptu.swp391.shoppingcart.authentication.service;
+
+import fptu.swp391.shoppingcart.authentication.model.CustomUserDetails;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AuthenticationProviderService implements AuthenticationProvider {
+ @Autowired
+ private JpaUserDetailsService userDetailsService;
+
+ @Autowired
+ private BCryptPasswordEncoder bCryptPasswordEncoder;
+
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+ String username = authentication.getName();
+ String password = authentication.getCredentials().toString();
+
+ CustomUserDetails userDetails = userDetailsService.loadUserByUsername(username);
+
+ if (bCryptPasswordEncoder.matches(password, userDetails.getPassword())) {
+ return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
+ }
+
+ throw new BadCredentialsException("Bad credentials");
+ }
+
+ @Override
+ public boolean supports(Class> authentication) {
+ return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
+ }
+}
diff --git a/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/service/JpaUserDetailsService.java b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/service/JpaUserDetailsService.java
new file mode 100644
index 0000000..d5f4351
--- /dev/null
+++ b/shopping-cart-backend/src/main/java/fptu/swp391/shoppingcart/authentication/service/JpaUserDetailsService.java
@@ -0,0 +1,27 @@
+package fptu.swp391.shoppingcart.authentication.service;
+
+import fptu.swp391.shoppingcart.authentication.entity.UserEntity;
+import fptu.swp391.shoppingcart.authentication.model.CustomUserDetails;
+import fptu.swp391.shoppingcart.authentication.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import java.util.function.Supplier;
+
+@Service
+public class JpaUserDetailsService implements UserDetailsService {
+ @Autowired
+ private UserRepository userRepository;
+
+ @Override
+ public CustomUserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ Supplier s =
+ () -> new UsernameNotFoundException("Problem during authentication!");
+
+ UserEntity u = userRepository.findUserByUsername(username).orElseThrow(s);
+
+ return new CustomUserDetails(u);
+ }
+}
diff --git a/shopping-cart-backend/src/test/java/fptu/swp391/shoppingcart/ShoppingCartApplicationTests.java b/shopping-cart-backend/src/test/java/fptu/swp391/shoppingcart/MainTests.java
similarity index 83%
rename from shopping-cart-backend/src/test/java/fptu/swp391/shoppingcart/ShoppingCartApplicationTests.java
rename to shopping-cart-backend/src/test/java/fptu/swp391/shoppingcart/MainTests.java
index 3cc01cc..cd8018b 100644
--- a/shopping-cart-backend/src/test/java/fptu/swp391/shoppingcart/ShoppingCartApplicationTests.java
+++ b/shopping-cart-backend/src/test/java/fptu/swp391/shoppingcart/MainTests.java
@@ -4,7 +4,7 @@
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
-class ShoppingCartApplicationTests {
+class MainTests {
@Test
void contextLoads() {