JWT tokens

This commit is contained in:
Lorenz Hohermuth 2025-07-04 16:33:01 +02:00
parent 3179d75ff7
commit ded05785dc
10 changed files with 143 additions and 1 deletions

View File

@ -94,6 +94,17 @@
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,35 @@
package ch.bbw.pr.tresorbackend.controller;
import ch.bbw.pr.tresorbackend.model.AuthRequest;
import ch.bbw.pr.tresorbackend.model.AuthResponse;
import ch.bbw.pr.tresorbackend.model.User;
import ch.bbw.pr.tresorbackend.repository.UserRepository;
import ch.bbw.pr.tresorbackend.service.PasswordEncryptionService;
import ch.bbw.pr.tresorbackend.util.JwtUtil;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
@RestController
@AllArgsConstructor
@RequestMapping("/api/auth")
public class AuthController {
private JwtUtil jwtUtil;
private UserRepository userRepository;
private PasswordEncryptionService passwordService;
@CrossOrigin(origins = "${CROSS_ORIGIN}")
@PostMapping("/")
public ResponseEntity<?> authentication(@Valid @RequestBody AuthRequest request) {
User user = userRepository.findByEmail(request.getEmail()).orElse(null);
if (user == null || !passwordService.verifyPassword(user, request.getPassword()) ) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
String token = jwtUtil.generateToken(user);
return ResponseEntity.ok(new AuthResponse(token));
}
}

View File

@ -4,6 +4,7 @@ import ch.bbw.pr.tresorbackend.model.*;
import ch.bbw.pr.tresorbackend.service.PasswordEncryptionService;
import ch.bbw.pr.tresorbackend.service.UserService;
import ch.bbw.pr.tresorbackend.util.Role;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@ -22,6 +23,7 @@ import java.util.stream.Collectors;
/**
* UserController
*
* @author Peter Rutschmann
*/
@RestController
@ -85,7 +87,8 @@ public class UserController {
registerUser.getLastName(),
registerUser.getEmail(),
passwordService.hashPassword(registerUser.getPassword()),
null
null,
Role.USER
);
User savedUser = userService.createUser(user);

View File

@ -0,0 +1,9 @@
package ch.bbw.pr.tresorbackend.model;
import lombok.Value;
@Value
public class AuthRequest {
String email;
String password;
}

View File

@ -0,0 +1,10 @@
package ch.bbw.pr.tresorbackend.model;
import lombok.Value;
@Value
public class AuthResponse {
String token;
public AuthResponse(String token) { this.token = token; }
public String getToken() { return token; }
}

View File

@ -1,5 +1,6 @@
package ch.bbw.pr.tresorbackend.model;
import ch.bbw.pr.tresorbackend.util.Role;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -35,4 +36,8 @@ public class User {
@Column(nullable = true)
private String two_fa_secret;
@Column(nullable = true)
@Enumerated(EnumType.STRING)
private Role role;
}

View File

@ -0,0 +1,29 @@
package ch.bbw.pr.tresorbackend.util;
import ch.bbw.pr.tresorbackend.model.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtil {
private final String SECRET = "secret-key";
public String generateToken(User user) {
return Jwts.builder()
.setSubject(user.getEmail())
.claim("role", user.getRole().name())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
.signWith(SignatureAlgorithm.HS256, SECRET.getBytes())
.compact();
}
public Claims validateToken(String token) throws ExpiredJwtException {
return Jwts.parser().setSigningKey(SECRET.getBytes()).parseClaimsJws(token).getBody();
}
}

View File

@ -0,0 +1,5 @@
package ch.bbw.pr.tresorbackend.util;
public enum Role {
USER, ADMIN
}

View File

@ -0,0 +1,32 @@
export const fetchJwtToken = async (loginValues) => {
const protocol = process.env.REACT_APP_API_PROTOCOL; // "http"
const host = process.env.REACT_APP_API_HOST; // "localhost"
const port = process.env.REACT_APP_API_PORT; // "8080"
const path = process.env.REACT_APP_API_PATH; // "/api"
const portPart = port ? `:${port}` : ''; // port is optional
const API_URL = `${protocol}://${host}${portPart}${path}`;
try {
const response = await fetch(`${API_URL}/auth/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: loginValues.email,
password: loginValues.password,
})
});
if (response.ok) {
const resJson = await response.json();
console.log(resJson)
console.log(resJson.token)
return resJson.token
}
throw new Error('jwttoken is not okey');
} catch (error) {
console.error('Failed to get jwt', error.message);
throw new Error('Failed to get jwt' || error.message);
}
};

View File

@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom';
import { loginUser, captchaCheck } from '../../comunication/FetchUser';
import ReCAPTCHA from 'react-google-recaptcha';
import { generate2FACode, verify2FACode } from '../../comunication/TwoFactorAuth';
import { fetchJwtToken } from '../../comunication/JwtToken';
/**
* LoginUser
@ -45,6 +46,8 @@ function LoginUser({ loginValues, setLoginValues }) {
const verify2FA = async () => {
const res = await verify2FACode({ loginValues, code });
if (res) {
const jwtToken = await fetchJwtToken(loginValues)
document.cookie = "jwtToken=" + jwtToken;
navigate('/')
return
}