FEAT: simple JWT | hardcoded usrname/password

This commit is contained in:
2026-06-10 17:07:42 +02:00
parent 143364592b
commit 0f4de8f859
13 changed files with 290 additions and 3 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

26
pom.xml
View File

@@ -63,6 +63,32 @@
<artifactId>hibernate-community-dialects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,23 @@
package com.mallardromain.hotel.DTO;
public class LoginRequest {
private String username;
private String 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;
}
}

View File

@@ -0,0 +1,42 @@
package com.mallardromain.hotel.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.mallardromain.hotel.security.JWTFilter;
@Configuration
public class SecurityConfig {
private final JWTFilter jwtFilter;
public SecurityConfig(JWTFilter jwtFilter) {
this.jwtFilter = jwtFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(
HttpSecurity http
) throws Exception {
http.csrf(csrf -> csrf.disable())
.sessionManagement(session ->
session.sessionCreationPolicy(
SessionCreationPolicy.STATELESS
)
)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(
jwtFilter,
UsernamePasswordAuthenticationFilter.class
);
return http.build();
}
}

View File

@@ -0,0 +1,54 @@
package com.mallardromain.hotel.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mallardromain.hotel.DTO.LoginRequest;
import com.mallardromain.hotel.service.JWTService;
@RestController
@RequestMapping("/auth")
public class AuthController {
private final JWTService jwtService;
public AuthController(JWTService jwtService){
this.jwtService = jwtService;
}
@PostMapping("/login")
public ResponseEntity<?> login(
@RequestBody LoginRequest request
){
//temps test1/2
if (
request.getUsername().equals("test1")
&&
request.getPassword().equals("password1")
) {
String token = jwtService
.generateToken(request.getUsername());
return ResponseEntity.ok(token);
}
if (
request.getUsername().equals("test2")
&&
request.getPassword().equals("password2")
) {
String token = jwtService
.generateToken(request.getUsername());
return ResponseEntity.ok(token);
}
return ResponseEntity.status(401).body("Invalid username/password");
}
}

View File

@@ -6,7 +6,7 @@ import org.springframework.web.bind.annotation.*;
import com.mallardromain.hotel.model.Room;
import com.mallardromain.hotel.repository.RoomRepository;
import com.mallardromain.hotel.repository.RoomService;
import com.mallardromain.hotel.service.RoomService;
@RestController
@RequestMapping("/rooms")

View File

@@ -0,0 +1,6 @@
package com.mallardromain.hotel.model;
public class JWT {
}

View File

@@ -7,6 +7,7 @@ import jakarta.persistence.*;
public class Room {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String number;
@@ -19,7 +20,7 @@ public class Room {
}
public Room(Integer id, String number, String status){
this.id = id;
//this.id = id; id is/should be generated by the DB
this.number = number;
this.status = status;
}

View File

@@ -0,0 +1,75 @@
package com.mallardromain.hotel.security;
import java.io.IOException;
import java.util.Collections;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.mallardromain.hotel.service.JWTService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Component
public class JWTFilter extends OncePerRequestFilter {
private final JWTService jwtService;
public JWTFilter(JWTService jwtService){
this.jwtService = jwtService;
}
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
String authHeader = request
.getHeader("Authorization");
if ( authHeader == null
||
!authHeader.startsWith("Bearer ")
) {
filterChain.doFilter(request, response);
return;
}
String token = authHeader.substring(7);
if (jwtService.isTockenValid(token)){
String username = jwtService
.extractUsername(token);
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(
username,
null,
Collections.emptyList()
);
auth.setDetails(
new WebAuthenticationDetailsSource()
.buildDetails(request)
);
SecurityContextHolder.getContext()
.setAuthentication(auth);
}
filterChain.doFilter(request, response);
}
}

View File

@@ -0,0 +1,58 @@
package com.mallardromain.hotel.service;
import java.security.Key;
import java.util.Date;
import javax.crypto.SecretKey;
import org.springframework.stereotype.Service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
@Service
public class JWTService {
private static final String SECRET = "NotHardCodedKeyThatIsAtLeast32CharactersLong!";
private final Key key = Keys.hmacShaKeyFor(SECRET.getBytes());
public String generateToken(String username){
return Jwts.builder()
.subject(username)
.issuedAt(new Date())
.expiration(
new Date(System.currentTimeMillis() + 1000 * 60 * 60)
)
.signWith(key)
.compact();
}
public boolean isTockenValid(String token){
try {
Jwts.parser()
.verifyWith((SecretKey) key)
.build()
.parseSignedClaims(token);
return true;
} catch (Exception e) {
return false;
}
}
public String extractUsername(String token){
Claims claims = Jwts.parser()
.verifyWith((SecretKey) key)
.build()
.parseSignedClaims(token)
.getPayload();
return claims.getSubject();
}
}

View File

@@ -1,10 +1,12 @@
package com.mallardromain.hotel.repository;
package com.mallardromain.hotel.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.mallardromain.hotel.model.Room;
import com.mallardromain.hotel.repository.RoomRepository;
import jakarta.persistence.*;
@Service