Skip to content

Commit

Permalink
Merge pull request #3 from thongdanghoang/feature/auth
Browse files Browse the repository at this point in the history
feat: user authentication with httpBasic
  • Loading branch information
thongdanghoang authored Sep 12, 2023
2 parents 8f4c82a + 3ea2ce5 commit f2be22a
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 8 deletions.
7 changes: 3 additions & 4 deletions shopping-cart-backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring-boot.version}</version>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
Expand Down
2 changes: 1 addition & 1 deletion shopping-cart-backend/shopping-cart.iml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="SonarLintModuleSettings">
<option name="uniqueId" value="f9191aba-e1f6-4c69-8236-d02c6617288d" />
<option name="uniqueId" value="042c3486-cc76-4a26-9870-da4929abf0f5" />
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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<Authority> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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<UserEntity, Integer> {
Optional<UserEntity> findUserByUsername(String username);
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<UsernameNotFoundException> s =
() -> new UsernameNotFoundException("Problem during authentication!");

UserEntity u = userRepository.findUserByUsername(username).orElseThrow(s);

return new CustomUserDetails(u);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ShoppingCartApplicationTests {
class MainTests {

@Test
void contextLoads() {
Expand Down

0 comments on commit f2be22a

Please sign in to comment.