Skip to content

Commit 1fea1bf

Browse files
committed
Creating a Spring Security Key for Signing a JWT Token
1 parent 5eca855 commit 1fea1bf

13 files changed

Lines changed: 228 additions & 147 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
package com.baeldung.jwtsignkey;
22

3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
6+
7+
@SpringBootApplication
8+
@EnableWebMvc
39
public class SpringJwtApplication {
10+
11+
public static void main(String[] args) {
12+
SpringApplication.run(com.baeldung.jwtsignkey.SpringJwtApplication.class);
13+
}
414
}

spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/jwtsignkey/controller/JwtAuthController.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,25 @@
33
import com.baeldung.jwtsignkey.jwtconfig.JwtUtils;
44
import com.baeldung.jwtsignkey.model.User;
55
import com.baeldung.jwtsignkey.repository.UserRepository;
6+
import com.baeldung.jwtsignkey.response.JwtResponse;
67
import com.baeldung.jwtsignkey.userservice.UserDetailsImpl;
8+
import com.baeldung.request.LoginRequest;
79
import jakarta.servlet.http.HttpServletRequest;
810
import org.springframework.beans.factory.annotation.Autowired;
911
import org.springframework.http.ResponseEntity;
12+
import org.springframework.security.access.prepost.PreAuthorize;
1013
import org.springframework.security.authentication.AuthenticationManager;
1114
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1215
import org.springframework.security.core.Authentication;
1316
import org.springframework.security.core.context.SecurityContextHolder;
1417
import org.springframework.security.crypto.password.PasswordEncoder;
15-
import org.springframework.web.bind.annotation.CrossOrigin;
1618
import org.springframework.web.bind.annotation.PostMapping;
1719
import org.springframework.web.bind.annotation.RequestBody;
20+
import org.springframework.web.bind.annotation.RequestMapping;
1821
import org.springframework.web.bind.annotation.RestController;
1922

2023
import java.io.UnsupportedEncodingException;
2124

22-
@CrossOrigin(origins = "*", maxAge = 3600)
2325
@RestController
2426
public class JwtAuthController {
2527

@@ -38,8 +40,10 @@ public class JwtAuthController {
3840
@PostMapping("/signup")
3941
public ResponseEntity<?> registerUser(@RequestBody User signUpRequest, HttpServletRequest request) throws UnsupportedEncodingException {
4042

41-
42-
// Create new user's account
43+
if (userRepository.existsByUsername(signUpRequest.getUsername())) {
44+
return ResponseEntity.badRequest()
45+
.body("Error: Username is already taken!");
46+
}
4347
User user = new User();
4448
user.setUsername(signUpRequest.getUsername());
4549
user.setPassword(encoder.encode(signUpRequest.getPassword()));
@@ -50,21 +54,24 @@ public ResponseEntity<?> registerUser(@RequestBody User signUpRequest, HttpServl
5054
}
5155

5256
@PostMapping("/signin")
53-
public ResponseEntity<?> authenticateUser( @RequestBody LoginRequest loginRequest) {
57+
public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {
5458

55-
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
59+
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
5660

57-
SecurityContextHolder.getContext()
58-
.setAuthentication(authentication);
61+
SecurityContextHolder.getContext()
62+
.setAuthentication(authentication);
5963
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
6064

61-
String jwt = jwtUtils.generateJwtToken(authentication);
62-
65+
String jwt = jwtUtils.generateJwtToken(authentication);
6366

67+
return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getUsername()));
6468

65-
return ResponseEntity.ok(
66-
new JwtResponse(jwt, userDetails.getUsername()));
69+
}
6770

71+
@RequestMapping("/user-dashboard")
72+
@PreAuthorize("isAuthenticated()")
73+
public String dashboard() {
74+
return "My Dashboard";
6875
}
6976

7077
}

spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/jwtsignkey/jwtconfig/AuthEntryPointJwt.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,22 @@
1818
@Component
1919
public class AuthEntryPointJwt implements AuthenticationEntryPoint {
2020

21-
private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);
21+
private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);
2222

23-
@Override
24-
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
25-
logger.error("Unauthorized error: {}", authException.getMessage());
23+
@Override
24+
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
25+
logger.error("Unauthorized error: {}", authException.getMessage());
2626

27-
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
28-
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
27+
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
28+
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
2929

30-
final Map<String, Object> body = new HashMap<>();
31-
body.put("status", HttpServletResponse.SC_UNAUTHORIZED);
32-
body.put("error", "Unauthorized");
33-
body.put("message", authException.getMessage());
34-
body.put("path", request.getServletPath());
30+
final Map<String, Object> body = new HashMap<>();
31+
body.put("status", HttpServletResponse.SC_UNAUTHORIZED);
32+
body.put("error", "Unauthorized");
33+
body.put("message", authException.getMessage());
34+
body.put("path", request.getServletPath());
3535

36-
final ObjectMapper mapper = new ObjectMapper();
37-
mapper.writeValue(response.getOutputStream(), body);
38-
}
36+
final ObjectMapper mapper = new ObjectMapper();
37+
mapper.writeValue(response.getOutputStream(), body);
38+
}
3939
}

spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/jwtsignkey/jwtconfig/AuthTokenFilter.java

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,46 +18,42 @@
1818
import java.io.IOException;
1919

2020
public class AuthTokenFilter extends OncePerRequestFilter {
21-
@Autowired
22-
private JwtUtils jwtUtils;
23-
24-
@Autowired
25-
private UserDetailsServiceImpl userDetailsService;
26-
27-
private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);
28-
29-
@Override
30-
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
31-
throws ServletException, IOException {
32-
try {
33-
String jwt = parseJwt(request);
34-
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
35-
String username = jwtUtils.getUserNameFromJwtToken(jwt);
36-
37-
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
38-
UsernamePasswordAuthenticationToken authentication =
39-
new UsernamePasswordAuthenticationToken(
40-
userDetails,
41-
null,
42-
userDetails.getAuthorities());
43-
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
44-
45-
SecurityContextHolder.getContext().setAuthentication(authentication);
46-
}
47-
} catch (Exception e) {
48-
logger.error("Cannot set user authentication: {}", e);
49-
}
21+
@Autowired
22+
private JwtUtils jwtUtils;
23+
24+
@Autowired
25+
private UserDetailsServiceImpl userDetailsService;
26+
27+
private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);
28+
29+
@Override
30+
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
31+
try {
32+
String jwt = parseJwt(request);
33+
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
34+
String username = jwtUtils.getUserNameFromJwtToken(jwt);
5035

51-
filterChain.doFilter(request, response);
52-
}
36+
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
37+
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
38+
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
5339

54-
private String parseJwt(HttpServletRequest request) {
55-
String headerAuth = request.getHeader("Authorization");
40+
SecurityContextHolder.getContext()
41+
.setAuthentication(authentication);
42+
}
43+
} catch (Exception e) {
44+
logger.error("Cannot set user authentication: {}", e);
45+
}
5646

57-
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
58-
return headerAuth.substring(7, headerAuth.length());
47+
filterChain.doFilter(request, response);
5948
}
6049

61-
return null;
62-
}
50+
private String parseJwt(HttpServletRequest request) {
51+
String headerAuth = request.getHeader("Authorization");
52+
53+
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
54+
return headerAuth.substring(7, headerAuth.length());
55+
}
56+
57+
return null;
58+
}
6359
}
Lines changed: 61 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package com.baeldung.jwtsignkey.jwtconfig;
22

33
import com.baeldung.jwtsignkey.userservice.UserDetailsImpl;
4-
import io.jsonwebtoken.*;
4+
5+
import io.jsonwebtoken.ExpiredJwtException;
6+
import io.jsonwebtoken.Jwts;
7+
import io.jsonwebtoken.MalformedJwtException;
8+
import io.jsonwebtoken.UnsupportedJwtException;
59
import io.jsonwebtoken.security.Keys;
10+
import io.jsonwebtoken.security.SignatureException;
611
import org.slf4j.Logger;
712
import org.slf4j.LoggerFactory;
813
import org.springframework.beans.factory.annotation.Value;
@@ -15,55 +20,62 @@
1520

1621
@Component
1722
public class JwtUtils {
18-
private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
19-
20-
@Value("${baeldung.app.jwtSecret}")
21-
private String jwtSecret;
22-
23-
@Value("${baeldung.app.jwtExpirationMs}")
24-
private int jwtExpirationMs;
25-
26-
public String generateJwtToken(Authentication authentication) {
27-
28-
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
29-
30-
return Jwts.builder()
31-
.setSubject((userPrincipal.getUsername()))
32-
.setIssuedAt(new Date())
33-
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
34-
.signWith(getSigningKey())
35-
.compact();
36-
37-
}
38-
39-
private Key getSigningKey() {
40-
byte[] keyBytes = this.jwtSecret.getBytes(StandardCharsets.UTF_8);
41-
return Keys.hmacShaKeyFor(keyBytes);
42-
}
43-
44-
public String getUserNameFromJwtToken(String token) {
45-
//return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
46-
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody().getSubject();
47-
48-
}
49-
50-
public boolean validateJwtToken(String authToken) {
51-
try {
52-
Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(authToken);
53-
return true;
54-
} catch (SignatureException e) {
55-
logger.error("Invalid JWT signature: {}", e.getMessage());
56-
} catch (MalformedJwtException e) {
57-
logger.error("Invalid JWT token: {}", e.getMessage());
58-
} catch (ExpiredJwtException e) {
59-
logger.error("JWT token is expired: {}", e.getMessage());
60-
} catch (UnsupportedJwtException e) {
61-
logger.error("JWT token is unsupported: {}", e.getMessage());
62-
} catch (IllegalArgumentException e) {
63-
logger.error("JWT claims string is empty: {}", e.getMessage());
23+
private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
24+
25+
@Value("${baeldung.app.jwtSecret}")
26+
private String jwtSecret;
27+
28+
@Value("${baeldung.app.jwtExpirationMs}")
29+
private int jwtExpirationMs;
30+
31+
public String generateJwtToken(Authentication authentication) {
32+
33+
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
34+
35+
return Jwts.builder()
36+
.subject((userPrincipal.getUsername()))
37+
.issuedAt(new Date())
38+
.expiration(new Date((new Date()).getTime() + jwtExpirationMs))
39+
.signWith(getSigningKey())
40+
.compact();
41+
6442
}
6543

66-
return false;
67-
}
44+
private Key getSigningKey() {
45+
byte[] keyBytes = this.jwtSecret.getBytes(StandardCharsets.UTF_8);
46+
return Keys.hmacShaKeyFor(keyBytes);
47+
}
48+
49+
public String getUserNameFromJwtToken(String token) {
50+
return Jwts.parser()
51+
.setSigningKey(getSigningKey())
52+
.build()
53+
.parseSignedClaims(token)
54+
.getPayload()
55+
.getSubject();
56+
57+
}
58+
59+
public boolean validateJwtToken(String authToken) {
60+
try {
61+
Jwts.parser()
62+
.setSigningKey(getSigningKey())
63+
.build()
64+
.parseSignedClaims(authToken);
65+
return true;
66+
} catch (SignatureException e) {
67+
logger.error("Invalid JWT signature: {}", e.getMessage());
68+
} catch (MalformedJwtException e) {
69+
logger.error("Invalid JWT token: {}", e.getMessage());
70+
} catch (ExpiredJwtException e) {
71+
logger.error("JWT token is expired: {}", e.getMessage());
72+
} catch (UnsupportedJwtException e) {
73+
logger.error("JWT token is unsupported: {}", e.getMessage());
74+
} catch (IllegalArgumentException e) {
75+
logger.error("JWT claims string is empty: {}", e.getMessage());
76+
}
77+
78+
return false;
79+
}
6880

6981
}

spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/jwtsignkey/repository/UserRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
public interface UserRepository extends JpaRepository<User, Long> {
99

10+
Boolean existsByUsername(String username);
11+
1012
Optional<User> findByUsername(String username);
1113

1214
}

spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/jwtsignkey/JwtResponse.java renamed to spring-security-modules/spring-security-core-2/src/main/java/com/baeldung/jwtsignkey/response/JwtResponse.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
package com.baeldung.jwtsignkey;
1+
package com.baeldung.jwtsignkey.response;
22

33
public class JwtResponse {
44
private String token;
55
private String type = "Bearer";
66

77
private String username;
88

9-
109
public JwtResponse(String accessToken, String username) {
1110
this.token = accessToken;
1211
this.username = username;

0 commit comments

Comments
 (0)