diff --git a/183_12_1_tresorbackend_rupe-master/pom.xml b/183_12_1_tresorbackend_rupe-master/pom.xml index 5804d6d..119064b 100644 --- a/183_12_1_tresorbackend_rupe-master/pom.xml +++ b/183_12_1_tresorbackend_rupe-master/pom.xml @@ -94,6 +94,17 @@ 1.5.0 + + io.jsonwebtoken + jjwt + 0.9.1 + + + + org.glassfish.jaxb + jaxb-runtime + 2.3.1 + diff --git a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/controller/AuthController.java b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/controller/AuthController.java new file mode 100644 index 0000000..82409fb --- /dev/null +++ b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/controller/AuthController.java @@ -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)); + } +} \ No newline at end of file diff --git a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/controller/UserController.java b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/controller/UserController.java index 160c754..6aa7e57 100644 --- a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/controller/UserController.java +++ b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/controller/UserController.java @@ -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); diff --git a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/AuthRequest.java b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/AuthRequest.java new file mode 100644 index 0000000..66afedc --- /dev/null +++ b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/AuthRequest.java @@ -0,0 +1,9 @@ +package ch.bbw.pr.tresorbackend.model; + +import lombok.Value; + +@Value +public class AuthRequest { + String email; + String password; +} diff --git a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/AuthResponse.java b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/AuthResponse.java new file mode 100644 index 0000000..eb444bd --- /dev/null +++ b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/AuthResponse.java @@ -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; } +} diff --git a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/User.java b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/User.java index a0a6958..aa8b310 100644 --- a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/User.java +++ b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/model/User.java @@ -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; } \ No newline at end of file diff --git a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/util/JwtUtil.java b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/util/JwtUtil.java new file mode 100644 index 0000000..adfa510 --- /dev/null +++ b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/util/JwtUtil.java @@ -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(); + } +} \ No newline at end of file diff --git a/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/util/Role.java b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/util/Role.java new file mode 100644 index 0000000..60c65c5 --- /dev/null +++ b/183_12_1_tresorbackend_rupe-master/src/main/java/ch/bbw/pr/tresorbackend/util/Role.java @@ -0,0 +1,5 @@ +package ch.bbw.pr.tresorbackend.util; + +public enum Role { + USER, ADMIN +} \ No newline at end of file diff --git a/183_12_2_tresorfrontend_rupe-master/src/comunication/JwtToken.js b/183_12_2_tresorfrontend_rupe-master/src/comunication/JwtToken.js new file mode 100644 index 0000000..e824a95 --- /dev/null +++ b/183_12_2_tresorfrontend_rupe-master/src/comunication/JwtToken.js @@ -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); + } +}; diff --git a/183_12_2_tresorfrontend_rupe-master/src/pages/user/LoginUser.jsx b/183_12_2_tresorfrontend_rupe-master/src/pages/user/LoginUser.jsx index 5135ede..f2426a9 100644 --- a/183_12_2_tresorfrontend_rupe-master/src/pages/user/LoginUser.jsx +++ b/183_12_2_tresorfrontend_rupe-master/src/pages/user/LoginUser.jsx @@ -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 }