-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from ONAV-KEA/user-system
User system
- Loading branch information
Showing
17 changed files
with
591 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
src/main/java/dk/kea/onav2ndproject_rest/JwtAuthenticationEntryPoint.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package dk.kea.onav2ndproject_rest; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import org.springframework.security.core.AuthenticationException; | ||
import org.springframework.security.web.AuthenticationEntryPoint; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.IOException; | ||
import java.io.Serializable; | ||
|
||
@Component | ||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, | ||
Serializable { | ||
@Override | ||
public void commence(HttpServletRequest request, HttpServletResponse response, | ||
AuthenticationException authException) throws IOException { | ||
System.out.println("JwtAuthenticationEntryPoint commence"); | ||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Unauthorized"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package dk.kea.onav2ndproject_rest; | ||
|
||
import dk.kea.onav2ndproject_rest.service.JwtUserDetailsService; | ||
import jakarta.servlet.FilterChain; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
|
||
import lombok.AllArgsConstructor; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.filter.OncePerRequestFilter; | ||
|
||
import java.io.IOException; | ||
|
||
@AllArgsConstructor | ||
@Component | ||
public class JwtFilter extends OncePerRequestFilter { | ||
private JwtUserDetailsService userDetailsService; | ||
private JwtTokenManager jwtTokenManager; | ||
@Override | ||
protected void doFilterInternal(HttpServletRequest request, | ||
HttpServletResponse response, FilterChain filterChain) | ||
throws ServletException, IOException { | ||
String tokenHeader = request.getHeader("Authorization"); | ||
System.out.println("JwtFilter doFilterInternal call 3 request header" + tokenHeader ); // + JwtController.printHeader(request) | ||
String username = null; | ||
String token = null; | ||
if (tokenHeader != null && tokenHeader.startsWith("Bearer ")) { | ||
token = tokenHeader.substring(7); | ||
try { | ||
username = jwtTokenManager.getUsernameFromToken(token); | ||
} catch (Exception e) { | ||
System.out.println("Unable to get JWT Token"); | ||
} | ||
} else { | ||
System.out.println("String does not start with Bearer or tokenheader == NULL"); | ||
} | ||
validateToken(request, username, token); | ||
filterChain.doFilter(request, response); //possible: response.setHeader( "key",value); its up to you. | ||
} | ||
|
||
private void validateToken(HttpServletRequest request, String username, String token) { | ||
if (null != username && SecurityContextHolder.getContext().getAuthentication() == null) { | ||
UserDetails userDetails = userDetailsService.loadUserByUsername(username); | ||
if (jwtTokenManager.validateJwtToken(token, userDetails)) { | ||
UsernamePasswordAuthenticationToken | ||
authenticationToken = new UsernamePasswordAuthenticationToken( | ||
userDetails, null, | ||
userDetails.getAuthorities()); | ||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); | ||
SecurityContextHolder.getContext().setAuthentication(authenticationToken); | ||
} | ||
} | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
src/main/java/dk/kea/onav2ndproject_rest/JwtTokenManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package dk.kea.onav2ndproject_rest; | ||
|
||
import io.jsonwebtoken.Claims; | ||
import io.jsonwebtoken.Jwts; | ||
import io.jsonwebtoken.SignatureAlgorithm; | ||
import io.jsonwebtoken.io.Decoders; | ||
import io.jsonwebtoken.security.Keys; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.security.Key; | ||
import java.util.Date; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
@Component | ||
public class JwtTokenManager { | ||
public static final long TOKEN_VALIDITY = 10 * 60 * 60 * 1000; // 10 timer | ||
// aha: Below is the server's private key. Which is used to generate new tokens. Length: Minimum 512 bits. | ||
// Which corresponds to minimum 86 characters in cleartext. | ||
@Value("${secret}") | ||
private String jwtSecret; | ||
public String generateJwtToken(UserDetails userDetails) { | ||
System.out.println("TokenManager generateJwtToken(UserDetails) call: 7"); | ||
Map<String, Object> claims = new HashMap<>(); | ||
return Jwts.builder().setClaims(claims).setSubject(userDetails.getUsername()) | ||
.setIssuedAt(new Date(System.currentTimeMillis())) | ||
.setExpiration(new Date(System.currentTimeMillis() + TOKEN_VALIDITY )) | ||
.signWith(getSignInKey(),SignatureAlgorithm.HS512 ) | ||
.compact(); | ||
//.signWith(SignatureAlgorithm.HS512, jwtSecret).compact(); // before Spring 3 | ||
} | ||
|
||
private Key getSignInKey() { | ||
byte[] keyBytes = Decoders.BASE64.decode(jwtSecret); | ||
return Keys.hmacShaKeyFor(keyBytes); | ||
} | ||
public Boolean validateJwtToken(String token, UserDetails userDetails) { | ||
System.out.println("TokenManager validateJwtToken(String token, UserDetails) With token: Call: B"); | ||
String username = getUsernameFromToken(token); | ||
Claims claims = getClaims(token); | ||
Boolean isTokenExpired = claims.getExpiration().before(new Date()); | ||
return (username.equals(userDetails.getUsername()) && !isTokenExpired); | ||
} | ||
public String getUsernameFromToken(String token) { | ||
System.out.println("TokenManager getUsernameFromToken(String token) With token: Call: A"); | ||
//Claims claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody(); // before Spring 3 | ||
Claims claims = getClaims(token); | ||
if(claims != null){ | ||
return claims.getSubject(); | ||
}else { | ||
return "no user found"; | ||
} | ||
} | ||
|
||
private Claims getClaims(String token){ | ||
try{ | ||
Claims claims = Jwts | ||
.parserBuilder() | ||
.setSigningKey(getSignInKey()) | ||
.build() | ||
.parseClaimsJws(token) | ||
.getBody(); | ||
return claims; | ||
}catch (Exception e){ | ||
System.out.println("could not parse JWT token for claims"); | ||
} | ||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/main/java/dk/kea/onav2ndproject_rest/api/UserController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package dk.kea.onav2ndproject_rest.api; | ||
|
||
import dk.kea.onav2ndproject_rest.JwtTokenManager; | ||
import dk.kea.onav2ndproject_rest.entity.JwtRequestModel; | ||
import dk.kea.onav2ndproject_rest.entity.JwtResponseModel; | ||
import dk.kea.onav2ndproject_rest.entity.User; | ||
import dk.kea.onav2ndproject_rest.service.IUserService; | ||
import dk.kea.onav2ndproject_rest.service.JwtUserDetailsService; | ||
import dk.kea.onav2ndproject_rest.service.UserService; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.authentication.AuthenticationManager; | ||
import org.springframework.security.authentication.BadCredentialsException; | ||
import org.springframework.security.authentication.DisabledException; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
@RestController | ||
@RequestMapping("/api/user") | ||
public class UserController { | ||
@Autowired | ||
private JwtUserDetailsService userDetailsService; | ||
@Autowired | ||
private AuthenticationManager authenticationManager; | ||
@Autowired | ||
private JwtTokenManager jwtTokenManager; | ||
@Autowired | ||
private IUserService userService; | ||
|
||
@PostMapping("/signup") | ||
public ResponseEntity<JwtResponseModel> signup(@RequestBody JwtRequestModel request){ | ||
System.out.println("signup: username:" + request.getUsername() + " password: " + request.getPassword() ); | ||
User user = new User(request.getUsername(),request.getPassword()); | ||
if(userService.findByName(user.getUsername()).size()==0) { | ||
if (userService.save(user) != null) { | ||
return ResponseEntity.ok(new JwtResponseModel("created user: " + user.getUsername() + " pw: " + user.getPassword())); | ||
} else { | ||
return ResponseEntity.ok(new JwtResponseModel("error creating user: " + user.getUsername())); | ||
} | ||
}else { | ||
return ResponseEntity.ok(new JwtResponseModel("error: user exists: " + user.getUsername())); | ||
} | ||
} | ||
|
||
@PostMapping("/login") | ||
public ResponseEntity<JwtResponseModel> createToken(@RequestBody JwtRequestModel request) throws Exception { | ||
// HttpServletRequest servletRequest is available from Spring, if needed. | ||
System.out.println(" JwtController createToken Call: 4" + request.getUsername()); | ||
try { | ||
authenticationManager.authenticate( | ||
new UsernamePasswordAuthenticationToken(request.getUsername(), | ||
request.getPassword()) | ||
); | ||
} catch (DisabledException e) { | ||
throw new Exception("USER_DISABLED", e); | ||
} catch (BadCredentialsException e) { | ||
return ResponseEntity.ok(new JwtResponseModel("bad credentials")); | ||
} | ||
final UserDetails userDetails = userDetailsService.loadUserByUsername(request.getUsername()); | ||
final String jwtToken = jwtTokenManager.generateJwtToken(userDetails); | ||
return ResponseEntity.ok(new JwtResponseModel(jwtToken)); | ||
} | ||
|
||
|
||
@PostMapping("/getSecret") | ||
public ResponseEntity<Map> getSecret() { | ||
System.out.println("getSecret is called"); | ||
Map<String,String > map = new HashMap<>(); | ||
map.put("message","this is secret from server"); | ||
return ResponseEntity.ok(map); | ||
} | ||
|
||
@DeleteMapping("/deleteUser") | ||
public ResponseEntity<Map> deleteUser(@RequestBody User user) { | ||
System.out.println("deleteUser is called with user: " + user.getUsername()); | ||
List<User> users = userService.findByName(user.getUsername()); | ||
User userToDelete = users.get(0); | ||
userService.delete(userToDelete); | ||
Map<String,String > map = new HashMap<>(); | ||
map.put("message","user deleted, if found " + user.getUsername()); | ||
return ResponseEntity.ok(map); | ||
} | ||
|
||
@GetMapping() | ||
public ResponseEntity<User> getUserByToken(@RequestParam String token){ | ||
System.out.println("getUserByToken is called with token: " + token); | ||
User user = userService.findByToken(token); | ||
return ResponseEntity.ok(user); | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
src/main/java/dk/kea/onav2ndproject_rest/config/InitData.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package dk.kea.onav2ndproject_rest.config; | ||
|
||
import dk.kea.onav2ndproject_rest.entity.Role; | ||
import dk.kea.onav2ndproject_rest.entity.User; | ||
import dk.kea.onav2ndproject_rest.repository.UserRepository; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.CommandLineRunner; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.util.Random; | ||
|
||
@Component | ||
public class InitData implements CommandLineRunner { | ||
|
||
@Autowired | ||
UserRepository userRepository; | ||
|
||
@Autowired | ||
private PasswordEncoder passwordEncoder; | ||
|
||
@Override | ||
public void run(String... args) throws Exception { | ||
User user1 = new User(); | ||
user1.setName("Anders"); | ||
user1.setId(31); | ||
user1.setEmail("[email protected]"); | ||
user1.setRole(Role.EMPLOYEE); | ||
user1.setPassword(passwordEncoder.encode("1234")); | ||
user1.setUsername("anders"); | ||
userRepository.save(user1); | ||
|
||
User user2 = new User(); | ||
user2.setName("Benny"); | ||
user2.setId(32); | ||
user2.setEmail("[email protected]"); | ||
user2.setRole(Role.MANAGER); | ||
user2.setPassword(passwordEncoder.encode("5678")); | ||
user2.setUsername("benny"); | ||
userRepository.save(user2); | ||
|
||
User user3 = new User(); | ||
user3.setName("Carla"); | ||
user3.setId(33); | ||
user3.setEmail("[email protected]"); | ||
user3.setRole(Role.EMPLOYEE); | ||
user3.setPassword(passwordEncoder.encode("9012")); | ||
user3.setUsername("carla"); | ||
userRepository.save(user3); | ||
|
||
User user4 = new User(); | ||
user4.setName("Dennis"); | ||
user4.setId(34); | ||
user4.setEmail("[email protected]"); | ||
user4.setRole(Role.HEADCHEF); | ||
user4.setPassword(passwordEncoder.encode("3456")); | ||
user4.setUsername("dennis"); | ||
userRepository.save(user4); | ||
|
||
User user5 = new User(); | ||
user5.setName("Eva"); | ||
user5.setId(35); | ||
user5.setEmail("[email protected]"); | ||
user5.setRole(Role.EMPLOYEE); | ||
user5.setPassword(passwordEncoder.encode("7890")); | ||
user5.setUsername("eva"); | ||
userRepository.save(user5); | ||
} | ||
} |
Oops, something went wrong.