I've been working on this for a while and the video I used to help me is from 2019 so it's a bit outdated but I thought that I could work through the problems. The program runs but when I try using postman I get a 401 unauthorized error:
Here is the jwtutil.java file code:
package com.stdbankjwtauth.authsystem.util;
import java.util.Map;
import java.util.function.Function;
import java.util.Date;
import java.util.HashMap;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@Service
public class JwtUtil {
private String SECRET_KEY = "secret";
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token,Claims::getExpiration);
}
public <T> T extractClaim(String token, Function<Claims,T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public String generateToken(UserDetails userDetails) {
Map<String,Object> claims = new HashMap<>();
return createToken(claims,userDetails.getUsername());
}
private String createToken(Map<String,Object> claims, String Subject) {
return Jwts.builder().setClaims(claims).setSubject(Subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis()+1000*60*60*10))
.signWith(SignatureAlgorithm.HS256,SECRET_KEY).compact();
}
public boolean validateToken(String token, UserDetails userDetails){
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
AuthenticationRequest.java
package com.stdbankjwtauth.authsystem.models;
public class AuthenticationRequest {
private String username;
private String password;
public AuthenticationRequest(String Username,String Password) {
this.username = Username;
this.password = Password;
}
public String getUsername() {
return username;
}
public void setUsername(String Username) {
this.username = Username;
}
public String getPassword() {
return password;
}
public void setPassword(String Password) {
this.password = Password;
}
}
AuthenticationResponse.java
package com.stdbankjwtauth.authsystem.models;
public class AuthenticationResponse {
private final String jwt;
public AuthenticationResponse(String Jwt) {
this.jwt = Jwt;
}
public String getJwt() {
return jwt;
}
}
AuthenticationEndpoint.java
package com.stdbankjwtauth.authsystem;
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.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.stdbankjwtauth.authsystem.models.AuthenticationRequest;
import com.stdbankjwtauth.authsystem.models.AuthenticationResponse;
import com.stdbankjwtauth.authsystem.util.JwtUtil;
@RestController
public class AuthenticateEnpoint {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtUtil jwtTokenUtil;
@PostMapping("/authenticates")
public ResponseEntity <?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws Exception{
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(),authenticationRequest.getPassword())
);
}catch(BadCredentialsException e) {
throw new Exception("Incorrect username or password",e);
}
final UserDetails userDetails = userDetailsService
.loadUserByUsername(authenticationRequest.getUsername());
final String jwt = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new AuthenticationResponse(jwt));
}
}
SecurityConfigurer
package com.stdbankjwtauth.authsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.http.SessionCreationPolicy;
@Configuration
@EnableWebSecurity
public class SecurirtyConfigurer extends WebSecurityConfiguration {
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.getDefaultUserDetailsService();
}
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.build();
}
protected void configure(HttpSecurity http) throws Exception{
http
.csrf()
.disable()
.authorizeHttpRequests().requestMatchers("/authenticates").permitAll()
.anyRequest().authenticated()
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
FileBasedAuthSystem.java
package com.stdbankjwtauth.authsystem.services;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.ArrayList;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
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.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.stereotype.Service;
@Configuration
@Service
public class FileBasedUserDetailsService {
private static final String FILE_PATH = "C:\\repos\\STDBank-JWT-Auth-System\\stdbank-jwt-auth\\credentials.txt";
@Bean
public InMemoryUserDetailsManager userDetailsService() {
List<String> lines = new ArrayList<>();
try {
lines = Files.readAllLines(Paths.get(FILE_PATH));
}catch (Exception e) {
e.printStackTrace();
}
for (String line : lines) {
String[] parts = line.split(":");
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
UserDetails user = User.withUsername(parts[0])
.password(encoder.encode(parts[1]))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
throw new UsernameNotFoundException("Username not found: "+ lines);
}
}
Here's a link to youtube video I used https://www.youtube.com/watch?v=X80nJ5T7YpE&t=81s
There could be a possiblity that JAXB library (Java Architecture for XML Binding) is missing in the classpath. JABX was there till java version 10 then it has removed from Java SE from Java 11 or newer, It is moved to Java EE under Jakarta EE project.
To fix this error, you can use the below options
For details you can visite here: https://www.codejava.net/coding/solved-java-lang-noclassdeffounderror-javax-xml-bind-jaxbexception