dużo lepsza autoryzacja teraz, dużo lepsza. Tokeny wygasają, można mieć tylko jeden aktywny token per user
This commit is contained in:
@@ -27,7 +27,6 @@ public class SecurityConfig {
|
|||||||
.csrf(AbstractHttpConfigurer::disable)
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers("/api/v1/auth/**").permitAll()
|
.requestMatchers("/api/v1/auth/**").permitAll()
|
||||||
.requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
|
|
||||||
.anyRequest().authenticated())
|
.anyRequest().authenticated())
|
||||||
.sessionManagement(session -> session
|
.sessionManagement(session -> session
|
||||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
|
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import _11.asktpk.artisanconnectbackend.entities.Client;
|
|||||||
import _11.asktpk.artisanconnectbackend.security.JwtUtil;
|
import _11.asktpk.artisanconnectbackend.security.JwtUtil;
|
||||||
import _11.asktpk.artisanconnectbackend.service.ClientService;
|
import _11.asktpk.artisanconnectbackend.service.ClientService;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@@ -12,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/auth")
|
@RequestMapping("/api/v1/auth")
|
||||||
public class AuthController {
|
public class AuthController {
|
||||||
@@ -33,6 +35,7 @@ public class AuthController {
|
|||||||
|
|
||||||
String token = jwtUtil.generateToken(client.getEmail(), userRole, userId);
|
String token = jwtUtil.generateToken(client.getEmail(), userRole, userId);
|
||||||
|
|
||||||
|
log.info("Logged in as " + client.getEmail());
|
||||||
return ResponseEntity.status(HttpStatus.OK)
|
return ResponseEntity.status(HttpStatus.OK)
|
||||||
.body(new AuthResponseDTO(userId, userRole, token));
|
.body(new AuthResponseDTO(userId, userRole, token));
|
||||||
} else {
|
} else {
|
||||||
@@ -54,6 +57,8 @@ public class AuthController {
|
|||||||
savedClient.getId()
|
savedClient.getId()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
log.info("Registered as " + savedClient.getEmail());
|
||||||
|
|
||||||
return ResponseEntity.status(HttpStatus.CREATED)
|
return ResponseEntity.status(HttpStatus.CREATED)
|
||||||
.body(new AuthResponseDTO(
|
.body(new AuthResponseDTO(
|
||||||
savedClient.getId(),
|
savedClient.getId(),
|
||||||
|
|||||||
@@ -36,8 +36,12 @@ public class JwtRequestFilter extends OncePerRequestFilter {
|
|||||||
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
|
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
|
||||||
jwt = authorizationHeader.substring(7);
|
jwt = authorizationHeader.substring(7);
|
||||||
|
|
||||||
if (jwtUtil.isBlacklisted(jwt)) {
|
if (jwtUtil.isBlacklisted(jwt) || !jwtUtil.isLatestToken(jwt)) {
|
||||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
response.setContentType("application/json");
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
String jsonResponse = "{\"error\": \"Token is invalid or expired. Please login again.\"}";
|
||||||
|
response.getWriter().write(jsonResponse);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import java.util.Date;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@@ -40,11 +37,27 @@ public class JwtUtil {
|
|||||||
return Keys.hmacShaKeyFor(secret.getBytes());
|
return Keys.hmacShaKeyFor(secret.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final Map<String, String> userActiveTokens = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public boolean isLatestToken(String token) {
|
||||||
|
String email = extractEmail(token);
|
||||||
|
String tokenId = extractTokenId(token);
|
||||||
|
String latestTokenId = userActiveTokens.get(email);
|
||||||
|
|
||||||
|
return latestTokenId != null && latestTokenId.equals(tokenId);
|
||||||
|
}
|
||||||
|
|
||||||
public String generateToken(String email, String role, Long userId) {
|
public String generateToken(String email, String role, Long userId) {
|
||||||
Map<String, Object> claims = new HashMap<>();
|
Map<String, Object> claims = new HashMap<>();
|
||||||
claims.put("role", role);
|
claims.put("role", role);
|
||||||
claims.put("userId", userId);
|
claims.put("userId", userId);
|
||||||
return createToken(claims, email);
|
claims.put("tokenId", UUID.randomUUID().toString());
|
||||||
|
|
||||||
|
String token = createToken(claims, email);
|
||||||
|
|
||||||
|
userActiveTokens.put(email, extractTokenId(token));
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createToken(Map<String, Object> claims, String subject) {
|
private String createToken(Map<String, Object> claims, String subject) {
|
||||||
@@ -57,6 +70,10 @@ public class JwtUtil {
|
|||||||
.compact();
|
.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String extractTokenId(String token) {
|
||||||
|
return extractAllClaims(token).get("tokenId", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
public String extractEmail(String token) {
|
public String extractEmail(String token) {
|
||||||
return extractClaim(token, Claims::getSubject);
|
return extractClaim(token, Claims::getSubject);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user