diff --git a/README.md b/README.md index a123dfb..e4ee052 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Learn to Implement this project: [Tutorial - Login Register in Spring Boot](http application.properties (change database settings) ``` #-------------------- server properties --------------- -server.port=8080 +server.port='Your port of choice' server.error.include-message=always #--------------------- Logging ------------------ @@ -19,14 +19,14 @@ logging.level.org.springframework.web=DEBUG logging.level.org.hibernate=ERROR #--------------------- DB Connection ------------------ -spring.datasource.url=jdbc:postgresql://localhost:5432/demo -spring.datasource.username=demo -spring.datasource.password=password +spring.datasource.url=jdbc:'your sql provider'://localhost:5432/demo +spring.datasource.username='username for your database' +spring.datasource.password='password to your database' #--------------------JPA-ORM Properties----------------- spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.'Your SQL dialect option' spring.jpa.properties.hibernate.format_sql=true ``` diff --git a/pom.xml b/pom.xml index 4bae3e6..4c1ef3b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.2 + 2.7.16 com.example @@ -14,7 +14,7 @@ Login Register Login Register Example for Spring Boot (Maven) - 17 + 21 @@ -35,8 +35,8 @@ - org.postgresql - postgresql + com.mysql + mysql-connector-j runtime @@ -58,6 +58,11 @@ org.thymeleaf.extras thymeleaf-extras-springsecurity5 + + org.projectlombok + lombok + true + @@ -65,6 +70,14 @@ org.springframework.boot spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + diff --git a/src/main/java/com/example/demo/config/CustomLoginSucessHandler.java b/src/main/java/com/example/demo/config/CustomLoginSuccessHandler.java similarity index 91% rename from src/main/java/com/example/demo/config/CustomLoginSucessHandler.java rename to src/main/java/com/example/demo/config/CustomLoginSuccessHandler.java index f979338..4f4c201 100644 --- a/src/main/java/com/example/demo/config/CustomLoginSucessHandler.java +++ b/src/main/java/com/example/demo/config/CustomLoginSuccessHandler.java @@ -15,7 +15,7 @@ import java.util.List; @Configuration -public class CustomLoginSucessHandler extends SimpleUrlAuthenticationSuccessHandler { +public class CustomLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { @Override protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { @@ -28,7 +28,7 @@ protected void handle(HttpServletRequest request, HttpServletResponse response, protected String determineTargetUrl(Authentication authentication){ String url = "/login?error=true"; Collection authorities = authentication.getAuthorities(); - List roles = new ArrayList(); + List roles = new ArrayList<>(); for(GrantedAuthority a : authorities){ roles.add(a.getAuthority()); } diff --git a/src/main/java/com/example/demo/config/WebSecurityConfig.java b/src/main/java/com/example/demo/config/WebSecurityConfig.java index 424e360..66ae996 100644 --- a/src/main/java/com/example/demo/config/WebSecurityConfig.java +++ b/src/main/java/com/example/demo/config/WebSecurityConfig.java @@ -1,6 +1,7 @@ package com.example.demo.config; import com.example.demo.service.UserServiceImpl; +import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -17,16 +18,10 @@ @Configuration @EnableWebSecurity +@AllArgsConstructor public class WebSecurityConfig { - @Autowired - private CustomLoginSucessHandler sucessHandler; - - @Bean - public UserDetailsService userDetailsService() { - return new UserServiceImpl(); - } - + private CustomLoginSuccessHandler successHandler; @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); @@ -37,31 +32,21 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration a return authConfig.getAuthenticationManager(); } - @Bean - public DaoAuthenticationProvider authenticationProvider() { - DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); - - authProvider.setUserDetailsService(userDetailsService()); - authProvider.setPasswordEncoder(passwordEncoder()); - - return authProvider; - } - @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeRequests() // URL matching for accessibility - .antMatchers("/", "/login", "/register").permitAll() + .antMatchers("/", "/auth/login", "/auth/register").permitAll() .antMatchers("/admin/**").hasAnyAuthority("ADMIN") .antMatchers("/account/**").hasAnyAuthority("USER") .anyRequest().authenticated() .and() // form login .csrf().disable().formLogin() - .loginPage("/login") - .failureUrl("/login?error=true") - .successHandler(sucessHandler) + .loginPage("/auth/login") + .failureUrl("/auth/login?error=true") + .successHandler(successHandler) .usernameParameter("email") .passwordParameter("password") .and() @@ -72,10 +57,6 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .and() .exceptionHandling() .accessDeniedPage("/access-denied"); - - http.authenticationProvider(authenticationProvider()); - http.headers().frameOptions().sameOrigin(); - return http.build(); } diff --git a/src/main/java/com/example/demo/controller/AdminController.java b/src/main/java/com/example/demo/controller/AdminController.java index b9d8feb..60812bf 100644 --- a/src/main/java/com/example/demo/controller/AdminController.java +++ b/src/main/java/com/example/demo/controller/AdminController.java @@ -1,13 +1,15 @@ package com.example.demo.controller; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller +@RequestMapping("/admin") public class AdminController { - @RequestMapping(value = {"/admin/dashboard"}, method = RequestMethod.GET) + @GetMapping("/dashboard") public String adminHome(){ return "admin/dashboard"; } diff --git a/src/main/java/com/example/demo/controller/AuthController.java b/src/main/java/com/example/demo/controller/AuthController.java index 659a394..bb49f5b 100644 --- a/src/main/java/com/example/demo/controller/AuthController.java +++ b/src/main/java/com/example/demo/controller/AuthController.java @@ -2,36 +2,39 @@ import com.example.demo.model.User; import com.example.demo.service.UserService; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.AllArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import javax.validation.Valid; import java.util.List; @Controller +@AllArgsConstructor +@RequestMapping("/auth") public class AuthController { - @Autowired + UserService userService; - @RequestMapping(value = {"/login"}, method = RequestMethod.GET) + @GetMapping("/login") public String login(){ return "auth/login"; } - @RequestMapping(value = {"/register"}, method = RequestMethod.GET) + @GetMapping("/register") public String register(Model model){ model.addAttribute("user", new User()); return "auth/register"; } - @RequestMapping(value = {"/register"}, method = RequestMethod.POST) + @PostMapping("/register") public String registerUser(Model model, @Valid User user, BindingResult bindingResult){ if(bindingResult.hasErrors()){ - model.addAttribute("successMessage", "User registered successfully!"); + model.addAttribute("errorMessage", "User not Registered!"); model.addAttribute("bindingResult", bindingResult); return "auth/register"; } diff --git a/src/main/java/com/example/demo/controller/UserController.java b/src/main/java/com/example/demo/controller/UserController.java index af8ea4f..b65ff31 100644 --- a/src/main/java/com/example/demo/controller/UserController.java +++ b/src/main/java/com/example/demo/controller/UserController.java @@ -1,13 +1,15 @@ package com.example.demo.controller; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller +@RequestMapping("/user") public class UserController { - @RequestMapping(value = {"/dashboard"}, method = RequestMethod.GET) + @GetMapping() public String homePage(){ return "user/dashboard"; } diff --git a/src/main/java/com/example/demo/model/Role.java b/src/main/java/com/example/demo/model/Role.java index aad0ca6..d4f37e4 100644 --- a/src/main/java/com/example/demo/model/Role.java +++ b/src/main/java/com/example/demo/model/Role.java @@ -1,5 +1,9 @@ package com.example.demo.model; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter public enum Role { USER("User"), ADMIN("Admin"); @@ -10,7 +14,4 @@ private Role(String value) { this.value = value; } - public String getValue() { - return value; - } } \ No newline at end of file diff --git a/src/main/java/com/example/demo/model/User.java b/src/main/java/com/example/demo/model/User.java index 423eb22..0fca644 100644 --- a/src/main/java/com/example/demo/model/User.java +++ b/src/main/java/com/example/demo/model/User.java @@ -1,8 +1,11 @@ package com.example.demo.model; +import lombok.Data; + import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import org.hibernate.validator.constraints.Length; + import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -10,12 +13,16 @@ import javax.persistence.*; import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; + import java.time.LocalDateTime; + + import java.util.Collection; import java.util.Collections; @Entity +@Data @Table(name = "users") public class User implements UserDetails { @SequenceGenerator( @@ -30,26 +37,30 @@ public class User implements UserDetails { ) private Long id; + @NotNull(message = "First Name cannot be empty") @Column(name = "first_name") private String firstName; + @NotNull(message = "Last Name cannot be empty") @Column(name = "last_name") private String lastName; + @NotNull(message = "Email cannot be empty") @Email(message = "Please enter a valid email address") @Column(name = "email", unique = true) private String email; @NotNull(message = "Password cannot be empty") - @Length(min = 7, message = "Password should be atleast 7 characters long") + @Length(min = 7, message = "Password should be at least 7 characters long") @Column(name = "password") private String password; + @Column(name = "mobile", unique = true) - @Length(min = 10, message = "Password should be atleast 10 number long") + @Length(min = 10, message = "Password should be at least 10 number long") private String mobile; @CreationTimestamp @@ -60,6 +71,7 @@ public class User implements UserDetails { @Column(name = "updated_at") private LocalDateTime updatedAt; + @Enumerated(EnumType.STRING) private Role role; @@ -108,26 +120,4 @@ public boolean isCredentialsNonExpired() { public boolean isEnabled() { return enabled; } - - public Role getRole() { return role; } - - public void setRole(com.example.demo.model.Role role) { - this.role = role; - } - - public String getEmail() { return email; } - - public void setEmail(String email) { this.email = email; } - - public String getFirstName() { return firstName; } - - public void setFirstName(String firstName) { this.firstName = firstName; } - - public String getMobile() { return mobile; } - - public void setMobile(String mobile) { this.mobile = mobile; } - - public String getLastName() { return lastName; } - - public void setLastName(String lastName) { this.lastName = lastName; } } diff --git a/src/main/java/com/example/demo/service/UserServiceImpl.java b/src/main/java/com/example/demo/service/UserServiceImpl.java index 32832dc..b16d9e2 100644 --- a/src/main/java/com/example/demo/service/UserServiceImpl.java +++ b/src/main/java/com/example/demo/service/UserServiceImpl.java @@ -2,31 +2,30 @@ import com.example.demo.model.User; import com.example.demo.repository.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; +import lombok.AllArgsConstructor; + import java.util.Arrays; import java.util.List; import java.util.Optional; @Service +@AllArgsConstructor public class UserServiceImpl implements UserService, UserDetailsService { - @Autowired BCryptPasswordEncoder bCryptPasswordEncoder; - @Autowired UserRepository userRepository; @Override public void saveUser(User user) { String encodedPassword = bCryptPasswordEncoder.encode(user.getPassword()); user.setPassword(encodedPassword); -// user.setRole(Role.USER); userRepository.save(user); } @@ -54,8 +53,8 @@ public List isUserPresent(User user) { @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { return userRepository.findByEmail(email).orElseThrow( - ()-> new UsernameNotFoundException( - String.format("USER_NOT_FOUND", email) + () -> new UsernameNotFoundException( + String.format("user with email %s not found", email) )); } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ce83caa..4cb2601 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,12 +9,13 @@ logging.level.org.springframework.web=DEBUG logging.level.org.hibernate=ERROR #--------------------- DB Connection ------------------ -spring.datasource.url=jdbc:postgresql://localhost:5432/matrimony -spring.datasource.username=matrimonyuser -spring.datasource.password=password +spring.datasource.url=jdbc:mysql://localhost:3306/login_register?createDatabaseIfNotExist=true +spring.datasource.username=root +spring.datasource.password=june12003 #--------------------JPA-ORM Properties----------------- spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect spring.jpa.properties.hibernate.format_sql=true + diff --git a/src/main/resources/templates/about-us.html b/src/main/resources/templates/about-us.html index c341232..8c115a2 100644 --- a/src/main/resources/templates/about-us.html +++ b/src/main/resources/templates/about-us.html @@ -1,9 +1,11 @@ - + + + About Us -

About Us

+

About Us

\ No newline at end of file diff --git a/src/main/resources/templates/access-denied.html b/src/main/resources/templates/access-denied.html index 26a782a..91a0486 100644 --- a/src/main/resources/templates/access-denied.html +++ b/src/main/resources/templates/access-denied.html @@ -1,9 +1,12 @@ - + + + Access Denied

Access Denied

+

OOPS, you are not allowed to access this end point. Contact your administrator

\ No newline at end of file diff --git a/src/main/resources/templates/admin/dashboard.html b/src/main/resources/templates/admin/dashboard.html index 9a140e2..eca1e6b 100644 --- a/src/main/resources/templates/admin/dashboard.html +++ b/src/main/resources/templates/admin/dashboard.html @@ -1,5 +1,6 @@ - + User Dashboard diff --git a/src/main/resources/templates/auth/login.html b/src/main/resources/templates/auth/login.html index 1acd9e2..fe7d693 100644 --- a/src/main/resources/templates/auth/login.html +++ b/src/main/resources/templates/auth/login.html @@ -1,15 +1,57 @@ - + + + Login - + +
+
+
+
+
+
+
Invalid Username or Password
+
+
+
You have been logged out
+
+
+
+

Login

+
+
+
+
+ + +
+
+ + +
+
+ +
+
+
+
+
+
+
diff --git a/src/main/resources/templates/auth/register.html b/src/main/resources/templates/auth/register.html index 9608f88..38034c2 100644 --- a/src/main/resources/templates/auth/register.html +++ b/src/main/resources/templates/auth/register.html @@ -1,28 +1,73 @@ + Login -
-

Registration

-

-

-

-

-

-

- | - -
-
    -
  • + +

    + +
    +
    +
    +
    +
    +

    Register

    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + Log in +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/src/main/resources/templates/homepage.html b/src/main/resources/templates/homepage.html index 6deb9e1..c1321fd 100644 --- a/src/main/resources/templates/homepage.html +++ b/src/main/resources/templates/homepage.html @@ -1,27 +1,52 @@ - + + Homepage -

    Welcome to Homepage

    -

    Text visible to anonymous.

    -

    Text visible to user.

    -

    Text visible to admin.

    -

    Text visible only to authenticated users.

    + +

    -
    -

    -

    -
    +
    +
    +

    Welcome to Homepage

    +

    Text visible to anonymous.

    +

    Text visible to user.

    +

    Text visible to admin.

    +

    Text visible only to authenticated users.

    + +
    +

    +

    +
    -
    -

    Logged as:

    -

    Has role:

    -

    -

    - Log out +
    +

    Logged as:

    +

    Has role:

    +

    +

    + Log out +
    +
    + \ No newline at end of file