Skip to content

Commit 49407e8

Browse files
committed
update to Spring Boot 3
1 parent f5a9253 commit 49407e8

File tree

13 files changed

+114
-59
lines changed

13 files changed

+114
-59
lines changed

README.md

+36-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Spring Boot Login example with Spring Security, MySQL and JWT
2+
Build a Spring Boot Login and Registration example (Rest API) that supports JWT with HttpOnly Cookie. You’ll know:
23

3-
- Appropriate Flow for User Login and Registration with JWT
4+
- Appropriate Flow for User Login and Registration with JWT and HttpOnly Cookies
45
- Spring Boot Rest Api Architecture with Spring Security
56
- How to configure Spring Security to work with JWT
67
- How to define Data Models and association for Authentication and Authorization
@@ -22,6 +23,11 @@ For more detail, please visit:
2223
2324
> [For MongoDB](https://www.bezkoder.com/spring-boot-jwt-auth-mongodb/)
2425
26+
Working with Front-end:
27+
> [Angular 12](https://www.bezkoder.com/angular-12-jwt-auth-httponly-cookie/) / [Angular 13](https://www.bezkoder.com/angular-13-jwt-auth-httponly-cookie/) / [Angular 14](https://www.bezkoder.com/angular-14-jwt-auth/) / [Angular 15](https://www.bezkoder.com/angular-15-jwt-auth/) / [Angular 16](https://www.bezkoder.com/angular-16-jwt-auth/)
28+
29+
> [React](https://www.bezkoder.com/react-login-example-jwt-hooks/) / [React Redux](https://www.bezkoder.com/redux-toolkit-auth/)
30+
2531
## Dependency
2632
– If you want to use PostgreSQL:
2733
```xml
@@ -34,8 +40,8 @@ For more detail, please visit:
3440
– or MySQL:
3541
```xml
3642
<dependency>
37-
<groupId>mysql</groupId>
38-
<artifactId>mysql-connector-java</artifactId>
43+
<groupId>com.mysql</groupId>
44+
<artifactId>mysql-connector-j</artifactId>
3945
<scope>runtime</scope>
4046
</dependency>
4147
```
@@ -54,7 +60,8 @@ spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.PostgreSQLDialect
5460
spring.jpa.hibernate.ddl-auto= update
5561
5662
# App Properties
57-
bezkoder.app.jwtSecret= bezKoderSecretKey
63+
bezkoder.app.jwtCookieName= bezkoder
64+
bezkoder.app.jwtSecret= ======================BezKoder=Spring===========================
5865
bezkoder.app.jwtExpirationMs= 86400000
5966
```
6067
- For MySQL
@@ -67,7 +74,8 @@ spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDiale
6774
spring.jpa.hibernate.ddl-auto= update
6875
6976
# App Properties
70-
bezkoder.app.jwtSecret= bezKoderSecretKey
77+
bezkoder.app.jwtCookieName= bezkoder
78+
bezkoder.app.jwtSecret= ======================BezKoder=Spring===========================
7179
bezkoder.app.jwtExpirationMs= 86400000
7280
```
7381
## Run Spring Boot application
@@ -93,14 +101,22 @@ INSERT INTO roles(name) VALUES('ROLE_ADMIN');
93101
94102
> [Spring Boot Repository Unit Test with @DataJpaTest](https://bezkoder.com/spring-boot-unit-test-jpa-repo-datajpatest/)
95103
104+
> [Spring Boot Rest Controller Unit Test with @WebMvcTest](https://www.bezkoder.com/spring-boot-webmvctest/)
105+
96106
> [Spring Boot Pagination & Sorting example](https://www.bezkoder.com/spring-boot-pagination-sorting-example/)
97107
108+
> Validation: [Spring Boot Validate Request Body](https://www.bezkoder.com/spring-boot-validate-request-body/)
109+
110+
> Documentation: [Spring Boot and Swagger 3 example](https://www.bezkoder.com/spring-boot-swagger-3/)
111+
112+
> Caching: [Spring Boot Redis Cache example](https://www.bezkoder.com/spring-boot-redis-cache-example/)
113+
98114
Associations:
99-
> [Spring Boot One To Many example with Spring JPA, Hibernate](https://www.bezkoder.com/jpa-one-to-many/)
115+
> [JPA/Hibernate One To Many example in Spring Boot](https://www.bezkoder.com/jpa-one-to-many/)
100116
101-
> [Spring Boot Many To Many example with Spring JPA, Hibernate](https://www.bezkoder.com/jpa-many-to-many/)
117+
> [JPA/Hibernate Many To Many example in Spring Boot](https://www.bezkoder.com/jpa-many-to-many/)
102118
103-
> [JPA One To One example with Spring Boot](https://www.bezkoder.com/jpa-one-to-one/)
119+
> [JPA/Hibernate One To One example in Spring Boot](https://www.bezkoder.com/jpa-one-to-one/)
104120
105121
Deployment:
106122
> [Deploy Spring Boot App on AWS – Elastic Beanstalk](https://www.bezkoder.com/deploy-spring-boot-aws-eb/)
@@ -147,6 +163,18 @@ Deployment:
147163
148164
> [Angular 14 + Spring Boot + PostgreSQL example](https://www.bezkoder.com/spring-boot-angular-14-postgresql/)
149165
166+
> [Angular 15 + Spring Boot + H2 Embedded Database example](https://www.bezkoder.com/spring-boot-angular-15-crud/)
167+
168+
> [Angular 15 + Spring Boot + MySQL example](https://www.bezkoder.com/spring-boot-angular-15-mysql/)
169+
170+
> [Angular 15 + Spring Boot + PostgreSQL example](https://www.bezkoder.com/spring-boot-angular-15-postgresql/)
171+
172+
> [Angular 16 + Spring Boot + H2 Embedded Database example](https://www.bezkoder.com/spring-boot-angular-16-crud/)
173+
174+
> [Angular 16 + Spring Boot + MySQL example](https://www.bezkoder.com/spring-boot-angular-16-mysql/)
175+
176+
> [Angular 16 + Spring Boot + PostgreSQL example](https://www.bezkoder.com/spring-boot-angular-16-postgresql/)
177+
150178
> [React + Spring Boot + MySQL example](https://www.bezkoder.com/react-spring-boot-crud/)
151179
152180
> [React + Spring Boot + PostgreSQL example](https://www.bezkoder.com/spring-boot-react-postgresql/)

pom.xml

+24-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>2.7.3</version>
8+
<version>3.1.0</version>
99
<relativePath/> <!-- lookup parent from repository -->
1010
</parent>
1111
<groupId>com.bezkoder</groupId>
@@ -14,7 +14,7 @@
1414
<name>spring-boot-login-example</name>
1515
<description>Spring Boot Login example with Spring Security, JWT and MySQL - Rest API</description>
1616
<properties>
17-
<java.version>1.8</java.version>
17+
<java.version>17</java.version>
1818
</properties>
1919
<dependencies>
2020
<dependency>
@@ -38,17 +38,31 @@
3838
</dependency>
3939

4040
<dependency>
41-
<groupId>mysql</groupId>
42-
<artifactId>mysql-connector-java</artifactId>
41+
<groupId>com.mysql</groupId>
42+
<artifactId>mysql-connector-j</artifactId>
4343
<scope>runtime</scope>
4444
</dependency>
4545

46-
<dependency>
47-
<groupId>io.jsonwebtoken</groupId>
48-
<artifactId>jjwt</artifactId>
49-
<version>0.9.1</version>
50-
</dependency>
51-
46+
<dependency>
47+
<groupId>io.jsonwebtoken</groupId>
48+
<artifactId>jjwt-api</artifactId>
49+
<version>0.11.5</version>
50+
</dependency>
51+
52+
<dependency>
53+
<groupId>io.jsonwebtoken</groupId>
54+
<artifactId>jjwt-impl</artifactId>
55+
<version>0.11.5</version>
56+
<scope>runtime</scope>
57+
</dependency>
58+
59+
<dependency>
60+
<groupId>io.jsonwebtoken</groupId>
61+
<artifactId>jjwt-jackson</artifactId>
62+
<version>0.11.5</version>
63+
<scope>runtime</scope>
64+
</dependency>
65+
5266
<dependency>
5367
<groupId>org.springframework.boot</groupId>
5468
<artifactId>spring-boot-starter-test</artifactId>

src/main/java/com/bezkoder/spring/login/controllers/AuthController.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import java.util.Set;
66
import java.util.stream.Collectors;
77

8-
import javax.validation.Valid;
8+
import jakarta.validation.Valid;
99

1010
import org.springframework.beans.factory.annotation.Autowired;
1111
import org.springframework.http.HttpHeaders;
@@ -34,6 +34,8 @@
3434
import com.bezkoder.spring.login.security.jwt.JwtUtils;
3535
import com.bezkoder.spring.login.security.services.UserDetailsImpl;
3636

37+
//for Angular Client (withCredentials)
38+
//@CrossOrigin(origins = "http://localhost:8081", maxAge = 3600, allowCredentials="true")
3739
@CrossOrigin(origins = "*", maxAge = 3600)
3840
@RestController
3941
@RequestMapping("/api/auth")

src/main/java/com/bezkoder/spring/login/controllers/TestController.java

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import org.springframework.web.bind.annotation.RequestMapping;
77
import org.springframework.web.bind.annotation.RestController;
88

9+
//for Angular Client (withCredentials)
10+
//@CrossOrigin(origins = "http://localhost:8081", maxAge = 3600, allowCredentials="true")
911
@CrossOrigin(origins = "*", maxAge = 3600)
1012
@RestController
1113
@RequestMapping("/api/test")

src/main/java/com/bezkoder/spring/login/models/Role.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.bezkoder.spring.login.models;
22

3-
import javax.persistence.*;
3+
import jakarta.persistence.*;
44

55
@Entity
66
@Table(name = "roles")

src/main/java/com/bezkoder/spring/login/models/User.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import java.util.HashSet;
44
import java.util.Set;
55

6-
import javax.persistence.*;
7-
import javax.validation.constraints.Email;
8-
import javax.validation.constraints.NotBlank;
9-
import javax.validation.constraints.Size;
6+
import jakarta.persistence.*;
7+
import jakarta.validation.constraints.Email;
8+
import jakarta.validation.constraints.NotBlank;
9+
import jakarta.validation.constraints.Size;
1010

1111
@Entity
1212
@Table(name = "users",

src/main/java/com/bezkoder/spring/login/payload/request/LoginRequest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.bezkoder.spring.login.payload.request;
22

3-
import javax.validation.constraints.NotBlank;
3+
import jakarta.validation.constraints.NotBlank;
44

55
public class LoginRequest {
66
@NotBlank

src/main/java/com/bezkoder/spring/login/payload/request/SignupRequest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import java.util.Set;
44

5-
import javax.validation.constraints.*;
5+
import jakarta.validation.constraints.*;
66

77
public class SignupRequest {
88
@NotBlank

src/main/java/com/bezkoder/spring/login/security/WebSecurityConfig.java

+13-11
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
88
//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
99
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
10-
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
10+
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
1111
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
1212
//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
1313
//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -23,10 +23,10 @@
2323

2424
@Configuration
2525
//@EnableWebSecurity
26-
@EnableGlobalMethodSecurity(
27-
// securedEnabled = true,
28-
// jsr250Enabled = true,
29-
prePostEnabled = true)
26+
@EnableMethodSecurity
27+
//(securedEnabled = true,
28+
//jsr250Enabled = true,
29+
//prePostEnabled = true) // by default
3030
public class WebSecurityConfig { // extends WebSecurityConfigurerAdapter {
3131
@Autowired
3232
UserDetailsServiceImpl userDetailsService;
@@ -84,12 +84,14 @@ public PasswordEncoder passwordEncoder() {
8484

8585
@Bean
8686
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
87-
http.cors().and().csrf().disable()
88-
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
89-
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
90-
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
91-
.antMatchers("/api/test/**").permitAll()
92-
.anyRequest().authenticated();
87+
http.csrf(csrf -> csrf.disable())
88+
.exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
89+
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
90+
.authorizeHttpRequests(auth ->
91+
auth.requestMatchers("/api/auth/**").permitAll()
92+
.requestMatchers("/api/test/**").permitAll()
93+
.anyRequest().authenticated()
94+
);
9395

9496
http.authenticationProvider(authenticationProvider());
9597

src/main/java/com/bezkoder/spring/login/security/jwt/AuthEntryPointJwt.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import java.util.HashMap;
55
import java.util.Map;
66

7-
import javax.servlet.ServletException;
8-
import javax.servlet.http.HttpServletRequest;
9-
import javax.servlet.http.HttpServletResponse;
7+
import jakarta.servlet.ServletException;
8+
import jakarta.servlet.http.HttpServletRequest;
9+
import jakarta.servlet.http.HttpServletResponse;
1010

1111
import org.slf4j.Logger;
1212
import org.slf4j.LoggerFactory;

src/main/java/com/bezkoder/spring/login/security/jwt/AuthTokenFilter.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import java.io.IOException;
44

5-
import javax.servlet.FilterChain;
6-
import javax.servlet.ServletException;
7-
import javax.servlet.http.HttpServletRequest;
8-
import javax.servlet.http.HttpServletResponse;
5+
import jakarta.servlet.FilterChain;
6+
import jakarta.servlet.ServletException;
7+
import jakarta.servlet.http.HttpServletRequest;
8+
import jakarta.servlet.http.HttpServletResponse;
99

1010
import org.slf4j.Logger;
1111
import org.slf4j.LoggerFactory;

src/main/java/com/bezkoder/spring/login/security/jwt/JwtUtils.java

+17-11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.bezkoder.spring.login.security.jwt;
22

3+
import java.security.Key;
34
import java.util.Date;
45

5-
import javax.servlet.http.Cookie;
6-
import javax.servlet.http.HttpServletRequest;
6+
import jakarta.servlet.http.Cookie;
7+
import jakarta.servlet.http.HttpServletRequest;
78

89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
@@ -14,6 +15,8 @@
1415

1516
import com.bezkoder.spring.login.security.services.UserDetailsImpl;
1617
import io.jsonwebtoken.*;
18+
import io.jsonwebtoken.io.Decoders;
19+
import io.jsonwebtoken.security.Keys;
1720

1821
@Component
1922
public class JwtUtils {
@@ -49,15 +52,18 @@ public ResponseCookie getCleanJwtCookie() {
4952
}
5053

5154
public String getUserNameFromJwtToken(String token) {
52-
return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
55+
return Jwts.parserBuilder().setSigningKey(key()).build()
56+
.parseClaimsJws(token).getBody().getSubject();
57+
}
58+
59+
private Key key() {
60+
return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));
5361
}
5462

5563
public boolean validateJwtToken(String authToken) {
5664
try {
57-
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
65+
Jwts.parserBuilder().setSigningKey(key()).build().parse(authToken);
5866
return true;
59-
} catch (SignatureException e) {
60-
logger.error("Invalid JWT signature: {}", e.getMessage());
6167
} catch (MalformedJwtException e) {
6268
logger.error("Invalid JWT token: {}", e.getMessage());
6369
} catch (ExpiredJwtException e) {
@@ -73,10 +79,10 @@ public boolean validateJwtToken(String authToken) {
7379

7480
public String generateTokenFromUsername(String username) {
7581
return Jwts.builder()
76-
.setSubject(username)
77-
.setIssuedAt(new Date())
78-
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
79-
.signWith(SignatureAlgorithm.HS512, jwtSecret)
80-
.compact();
82+
.setSubject(username)
83+
.setIssuedAt(new Date())
84+
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
85+
.signWith(key(), SignatureAlgorithm.HS256)
86+
.compact();
8187
}
8288
}
+5-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
spring.datasource.url= jdbc:mysql://localhost:3306/testdb?useSSL=false
1+
spring.datasource.url= jdbc:mysql://localhost:3306/testdb_spring?useSSL=false
22
spring.datasource.username= root
33
spring.datasource.password= 123456
44

5-
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
5+
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQLDialect
66
spring.jpa.hibernate.ddl-auto= update
77

88
# App Properties
99
bezkoder.app.jwtCookieName= bezkoder
10-
bezkoder.app.jwtSecret= bezKoderSecretKey
11-
bezkoder.app.jwtExpirationMs= 86400000
10+
bezkoder.app.jwtSecret= ======================BezKoder=Spring===========================
11+
bezkoder.app.jwtExpirationMs= 30000
12+
#86400000

0 commit comments

Comments
 (0)