Skip to content

Commit

Permalink
added roles
Browse files Browse the repository at this point in the history
  • Loading branch information
Petrovich-A committed Jul 4, 2023
1 parent 83fc826 commit 0006e0d
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
//@EnableWebSecurity(debug = true)
@EnableWebSecurity(debug = true)
@ComponentScan(basePackages = "by")
public class WebSecurityConfig {

Expand All @@ -21,6 +22,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.authorizeHttpRequests(requests -> requests
.requestMatchers("/javaScript/**", "/img/**", "/CSS/**").permitAll()
.requestMatchers("/", "/home", "/registration", "/users/registrate", "/login").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
Expand All @@ -33,6 +35,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
)
.logout(logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.invalidateHttpSession(true)
.clearAuthentication(true)
.permitAll()
);
return http.build();
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/by/petrovich/eshop/entity/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package by.petrovich.eshop.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.HashSet;
import java.util.Set;

@Data
@Entity
@NoArgsConstructor
@Table(name = "roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private Integer id;
@Column(nullable = false, unique = true)
private String name;
@OneToMany(mappedBy = "role")
private Set<User> users = new HashSet<>();
}
14 changes: 9 additions & 5 deletions src/main/java/by/petrovich/eshop/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Email;
Expand All @@ -31,7 +33,6 @@
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
@Entity
@EqualsAndHashCode
@Table(name = "users")
Expand All @@ -41,20 +42,23 @@ public class User {
@Column(name = "user_id")
private Integer userId;
@NotBlank(message = "Name is required")
@Column(unique=true)
@Column(unique = true)
private String name;
@Column(unique=true)
@Column(unique = true)
@NotBlank(message = "Password id is required")
private String password;
@Column(unique=true)
@Column(unique = true)
@Email(message = "Email is not valid")
private String email;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Past
private LocalDate birthDate;
@Column(columnDefinition="Decimal(10,2) default '0.00'")
@Column(columnDefinition = "Decimal(10,2) default '0.00'")
private BigDecimal balance;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade = CascadeType.ALL)
private Set<Order> orders = new HashSet<>();
@ManyToOne
@JoinColumn(name = "role_id", nullable = false)
private Role role;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package by.petrovich.eshop.repository;

import by.petrovich.eshop.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RoleRepository extends JpaRepository<Role, Integer> {
Role findByName(String name);

}
59 changes: 59 additions & 0 deletions src/main/java/by/petrovich/eshop/security/CustomUserDetails.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package by.petrovich.eshop.security;

import by.petrovich.eshop.entity.Order;
import by.petrovich.eshop.entity.Role;
import by.petrovich.eshop.entity.User;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Past;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Set;

public class CustomUserDetails extends User implements UserDetails {
public CustomUserDetails(Integer userId,
String name,
String password,
String email,
LocalDate birthDate,
BigDecimal balance,
Set<Order> orders,
Role role) {
super(userId, name, password, email, birthDate, balance, orders, role);
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
}

@Override
public String getUsername() {
return super.getName();
}

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

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

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

@Override
public boolean isEnabled() {
return true;
}
}
13 changes: 11 additions & 2 deletions src/main/java/by/petrovich/eshop/service/impl/UserServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import by.petrovich.eshop.exceptions.UserNotFoundException;
import by.petrovich.eshop.repository.RoleRepository;
import by.petrovich.eshop.repository.UserRepository;
import by.petrovich.eshop.security.CustomUserDetails;
import by.petrovich.eshop.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
Expand All @@ -15,7 +16,6 @@
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;

@Service
Expand Down Expand Up @@ -58,7 +58,16 @@ public void register(RegistrationFormDto registrationFormDto) {
public UserDetails loadUserByUsername(String name) throws UserNotFoundException {
User user = userRepository.findByName(name).orElseThrow(()
-> new UserNotFoundException("User not found"));
return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(), Collections.emptyList());
return new CustomUserDetails(
user.getUserId(),
user.getName(),
user.getPassword(),
user.getEmail(),
user.getBirthDate(),
user.getBalance(),
user.getOrders(),
user.getRole()
);
}

private boolean isExist(String email) {
Expand Down
10 changes: 10 additions & 0 deletions src/main/resources/db/migration/V1__Create_Eshop_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CREATE TABLE IF NOT EXISTS users
email text NOT NULL UNIQUE,
birth_date date NOT NULL,
balance NUMERIC(10, 2) DEFAULT '0.00',
role_id INTEGER,
PRIMARY KEY (user_id)
);

Expand Down Expand Up @@ -57,4 +58,13 @@ CREATE TABLE IF NOT EXISTS carts
user_id INTEGER,
PRIMARY KEY (cart_id),
CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users (user_id)
);

-- ROLES
--
CREATE TABLE IF NOT EXISTS roles
(
role_id SERIAL NOT NULL,
name varchar(20) NOT NULL,
PRIMARY KEY (role_id)
);
21 changes: 10 additions & 11 deletions src/main/resources/db/migration/V2__Populate_Eshop_tables.sql
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
INSERT INTO users (name, password, email, birth_date, balance)
values ('Wade', 'Williams', '[email protected]', '01-01-1990', 0.5),
('Dave', 'Harris', '[email protected]', '01-01-1990', 0.5),
('Seth', 'Thomas', '[email protected]', '01-01-1990', 0.5),
('Ivan', 'Robinson', '[email protected]', '01-01-1990', 0.5),
('Riley', 'Walker', '[email protected]', '01-01-1990', 0.5),
('Daisy', 'Scott', '[email protected]', '01-01-1990', 15.5),
('Deborah', 'Nelson', '[email protected]', '01-01-1990', 0.5),
('Stella', 'Morgan', '[email protected]', '01-01-1990', 0.5),
('Debra', 'Cooper', '[email protected]', '01-01-1990', 0.5);
INSERT INTO users (name, password, email, birth_date, balance, role_id)
values ('Wade', 'Williams', '[email protected]', '01-01-1990', 0.5, 1),
('Dave', 'Harris', '[email protected]', '01-01-1990', 0.5, 1),
('Seth', 'Thomas', '[email protected]', '01-01-1990', 15.5, 1),
('admin', '$2a$10$an1GB52whsATPp.1SulvUun3WnF.8c5k/4BgQwh4S/OpMr9wO.SDm', '[email protected]', '01-01-1990', 0.5, 2);

INSERT INTO categories (name, rating)
values ('category1', 1),
Expand Down Expand Up @@ -77,4 +72,8 @@ VALUES (0.10, 1, CURRENT_TIMESTAMP),
INSERT INTO carts (price, created_at, user_id)
VALUES (50.55, CURRENT_TIMESTAMP, 1),
(10.99, CURRENT_TIMESTAMP, 2),
(0.5, CURRENT_TIMESTAMP, 5);
(0.5, CURRENT_TIMESTAMP, 3);

INSERT INTO roles (name)
VALUES ('ROLE_USER'),
('ROLE_ADMIN');
8 changes: 4 additions & 4 deletions src/main/resources/templates/include/topnav.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<html xmlns:th="http:https://www.thymeleaf.org"
xmlns:sec="http:https://www.thymeleaf.org/thymeleaf-extras-springsecurity6" lang="en">
<html lang="en" xmlns:th="http:https://www.thymeleaf.org"
xmlns:sec="http:https://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<div class="topnav" th:fragment="navigation">
<img src="/img/e_shop_logo.png" alt="e-shop logo">
<a class="fa badge fa-5x" href="/home">&#xf015 Home</a>
Expand All @@ -10,10 +10,10 @@
<a class="fa badge fa-5x" href="profile">&#xf007 Profile</a>
<a class="fa badge-cart fa-5x" href="/cart" th:value="${session.cartDto.quantity}">&#xf07a Cart</a>
</div>
<!-- <div sec:authentication="principal.firstName"> Authenticated user's lastName:</div>-->
<div sec:authorize="hasRole('ROLE_ADMIN')">
<div sec:authorize="hasRole('ADMIN')">
<a class="fa badge fa-5x" href="admin">Admin</a>
</div>
<!-- <div sec:authentication="principal.firstName"> Authenticated user's lastName:</div>-->
<div class="search-container">
<form class="search-form" th:action="@{/product/search}">
<label><input type="text" placeholder="Search.." th:name="searchKey"></label>
Expand Down
30 changes: 20 additions & 10 deletions src/main/resources/templates/profile.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http:https://www.thymeleaf.org">
<html lang="en" xmlns:th="http:https://www.thymeleaf.org"
xmlns:sec="http:https://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<head>
<title>Profile page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
Expand All @@ -9,26 +10,35 @@
</head>
<body>
<div th:insert="~{include/topnav :: navigation}"></div>

<div class="card-profile">
<h2 style="text-align:center">User Profile Card</h2>
<img src="https://www.w3schools.com/w3images/team2.jpg" alt="John" style="width:100%">
<p class="title">Profile</p>
<h1 th:text="'name: ' + ${user.name}"></h1>
<p th:text="'email: ' + ${user.email}"></p>
<p th:text="'userId: ' + ${user.userId}"></p>
<span th:text="'balance: ' + ${user.balance}"></span>
<span>name: </span>
<span sec:authentication="principal.name"></span>
<span>id: </span>
<span sec:authentication="principal.userId"></span>
<h6></h6>
<span>email: </span>
<span sec:authentication="principal.email"></span>
<h6></h6>
<span>role: </span>
<span sec:authentication="principal.role.name"></span>
<h6></h6>
<span>balance: </span>
<span sec:authentication="principal.balance"></span>
<span class="price" th:utext="${'&#36;'+'&nbsp;'}"></span>
<p th:text="'birth date: ' + ${user.birthDate}"></p>
<h6></h6>
<span>birth date: </span>
<span sec:authentication="principal.birthDate"></span>
<div style="margin: 24px 0;">
<a href="#"><i class="fa fa-twitter"></i></a>
<a href="#"><i class="fa fa-linkedin"></i></a>
<a href="#"><i class="fa fa-facebook"></i></a>
</div>
<form th:action="@{'/order/read-history/' + ${user.userId}}" th:value="${cartDto}">
<form th:action="@{'/order/read-history/' + principal.userId}">
<button type="submit" class="order-btn">Orders history</button>
</form>
</div>
</body>
<div th:insert="~{include/footer :: footer}"></div>
</html>
</html>
23 changes: 23 additions & 0 deletions src/test/by/petrovich/eshop/repository/RoleRepositoryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package by.petrovich.eshop.repository;

import by.petrovich.eshop.entity.Role;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest
class RoleRepositoryTest {
@Autowired
private RoleRepository repository;

@Test
void findByName() {
Role expected = new Role();
expected.setName("user");

Role actual = repository.findByName(expected.getName());
assertEquals(actual, expected);
}
}

0 comments on commit 0006e0d

Please sign in to comment.