Skip to content

Commit 24e2102

Browse files
committed
Spring Application v5
1 parent 9239c2e commit 24e2102

12 files changed

Lines changed: 71 additions & 43 deletions

File tree

heroes/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/pg
2+
/grafana-data
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: 1
2+
3+
datasources:
4+
- name: Prometheus
5+
type: prometheus
6+
url: http://prometheus:9090
7+
isDefault: true
8+
access: proxy
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CREATE DATABASE rooms;
2+
\c rooms;
3+
SET search_path TO public;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
global:
2+
scrape_interval: 5s
3+
4+
scrape_configs:
5+
- job_name: 'heroes-application'
6+
metrics_path: '/actuator/prometheus'
7+
static_configs:
8+
- targets: ['host.docker.internal:9097']

heroes/docker-compose.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,30 @@ services:
44
container_name: heroes-db
55
restart: always
66
environment:
7-
POSTGRES_DB: postgres
7+
POSTGRES_DB: rooms
88
POSTGRES_USER: postgres
99
POSTGRES_PASSWORD: postgres
1010
ports:
1111
- "25432:5432"
1212
volumes:
1313
- ./pg:/var/lib/postgresql/data
14+
- ./configuration/postgres/pg_init.sql:/docker-entrypoint-initdb.d/init.sql
1415
healthcheck:
15-
test: [ "CMD-SHELL", "pg_isready -U postgres -d postgres" ]
16+
test: [ "CMD-SHELL", "pg_isready -U postgres -d rooms" ]
1617
interval: 5s
1718
timeout: 5s
1819
retries: 5
20+
prometheus:
21+
image: prom/prometheus
22+
ports:
23+
- "19090:9090"
24+
volumes:
25+
- ./configuration/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
26+
27+
grafana:
28+
image: grafana/grafana
29+
ports:
30+
- "13000:3000"
31+
volumes:
32+
- ./grafana-data:/var/lib/grafana
33+
- ./configuration/grafana/datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml

heroes/src/main/java/ru/mifi/practice/voln/configuration/SecurityConfiguration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,10 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht
128128
}
129129

130130
var jwt = authHeader.substring(BEARER_PREFIX.length());
131-
var username = jwtService.extractUserName(jwt);
131+
var userId = jwtService.extractUserId(jwt);
132132

133-
if (StringUtils.hasText(username) && SecurityContextHolder.getContext().getAuthentication() == null) {
134-
UserDetails userDetails = userService.loadUserByUsername(username);
133+
if (SecurityContextHolder.getContext().getAuthentication() == null && userId.isPresent()) {
134+
UserDetails userDetails = userService.loadUserById(userId.get());
135135
if (jwtService.isTokenValid(jwt, userDetails)) {
136136
SecurityContext context = SecurityContextHolder.createEmptyContext();
137137
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(

heroes/src/main/java/ru/mifi/practice/voln/controller/ChatController.java

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,64 +41,42 @@ public ChatController(UserPresenceService userPresenceService) {
4141
}
4242

4343
@GetMapping("/api/chat/connect")
44-
public SseEmitter connect(@RequestParam String username,
45-
HttpServletRequest request) {
46-
47-
// Генерируем уникальный ID сессии
44+
public SseEmitter connect(@RequestParam String username, HttpServletRequest request) {
4845
UUID sessionId = UUID.randomUUID();
49-
50-
// Проверяем, не занято ли имя пользователя (опционально)
5146
if (userPresenceService.isUsernameTaken(username)) {
5247
throw new ResponseStatusException(
5348
HttpStatus.CONFLICT,
5449
"Имя пользователя уже занято"
5550
);
5651
}
5752

58-
SseEmitter emitter = new SseEmitter(60L * 1000 * 60); // 60 минут timeout
59-
60-
// Создаем пользователя
53+
SseEmitter emitter = new SseEmitter(60L * 1000 * 60);
6154
RoomUser user = userPresenceService.addUser(username, sessionId, emitter);
62-
63-
// Отправляем информацию о пользователе
6455
Map<String, Object> userInfo = new HashMap<>();
6556
userInfo.put("sessionId", sessionId);
6657
userInfo.put("username", username);
6758
userInfo.put("connectedAt", user.connected());
6859

6960
try {
70-
// Отправляем данные о соединении
7161
emitter.send(SseEmitter.event()
7262
.name("connected")
7363
.data(userInfo));
74-
75-
// Отправляем историю сообщений
7664
for (RoomMessage message : messageHistory) {
7765
emitter.send(SseEmitter.event()
7866
.name("message")
7967
.data(message));
8068
}
81-
82-
// Отправляем текущий список пользователей
8369
sendUserListUpdate();
8470

8571
} catch (IOException e) {
8672
userPresenceService.removeUser(sessionId);
8773
emitter.completeWithError(e);
8874
}
75+
emitter.onCompletion(() -> handleUserDisconnect(sessionId, username, "disconnected"));
8976

90-
// Обработчики событий
91-
emitter.onCompletion(() -> {
92-
handleUserDisconnect(sessionId, username, "disconnected");
93-
});
94-
95-
emitter.onTimeout(() -> {
96-
handleUserDisconnect(sessionId, username, "timeout");
97-
});
77+
emitter.onTimeout(() -> handleUserDisconnect(sessionId, username, "timeout"));
9878

99-
emitter.onError((e) -> {
100-
handleUserDisconnect(sessionId, username, "error");
101-
});
79+
emitter.onError((e) -> handleUserDisconnect(sessionId, username, "error"));
10280

10381
return emitter;
10482
}

heroes/src/main/java/ru/mifi/practice/voln/domain/entity/AuthorityEntity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import jakarta.persistence.Table;
1313
import jakarta.persistence.UniqueConstraint;
1414
import lombok.Getter;
15+
import lombok.ToString;
1516
import org.springframework.security.core.GrantedAuthority;
1617

18+
@ToString(of = {"authority", "user"})
1719
@Getter
1820
@Entity
1921
@Table(name = "authorities", uniqueConstraints = @UniqueConstraint(columnNames = {"user_id", "authority"}))

heroes/src/main/java/ru/mifi/practice/voln/domain/entity/UserEntity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
import lombok.Builder;
1313
import lombok.Getter;
1414
import lombok.NoArgsConstructor;
15+
import lombok.ToString;
1516
import org.springframework.security.core.userdetails.UserDetails;
1617
import org.springframework.util.StringUtils;
1718

1819
import java.util.List;
1920
import java.util.UUID;
2021

22+
@ToString(exclude = "authorities")
2123
@Builder(toBuilder = true)
2224
@Getter
2325
@Entity

heroes/src/main/java/ru/mifi/practice/voln/service/JwtService.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import io.jsonwebtoken.Claims;
44
import io.jsonwebtoken.Jwts;
5-
import io.jsonwebtoken.SignatureAlgorithm;
65
import io.jsonwebtoken.io.Decoders;
76
import io.jsonwebtoken.security.Keys;
87
import lombok.RequiredArgsConstructor;
@@ -14,6 +13,8 @@
1413
import java.util.Date;
1514
import java.util.HashMap;
1615
import java.util.Map;
16+
import java.util.Optional;
17+
import java.util.UUID;
1718
import java.util.function.Function;
1819

1920
@Service
@@ -29,21 +30,26 @@ public String extractUserName(String token) {
2930
return extractClaim(token, Claims::getSubject);
3031
}
3132

33+
public Optional<UUID> extractUserId(String token) {
34+
return Optional.ofNullable(extractClaim(token, claims -> claims.get("user_id", String.class)))
35+
.map(UUID::fromString);
36+
}
37+
3238
public String generateToken(UserDetails userDetails) {
3339
Map<String, Object> claims = new HashMap<>();
34-
if (userDetails instanceof UserEntity customUserDetails) {
35-
claims.put("id", customUserDetails.getId());
36-
claims.put("email", customUserDetails.getEmail());
37-
claims.put("authorities", customUserDetails.getAuthorities());
40+
if (userDetails instanceof UserEntity entity) {
41+
claims.put("user_id", entity.getId());
42+
claims.put("username", entity.getUsername());
43+
claims.put("email", entity.getEmail());
44+
claims.put("authorities", entity.getAuthorities());
3845
}
3946
return generateToken(claims, userDetails);
4047
}
4148

4249
private String generateToken(Map<String, Object> extraClaims, UserDetails userDetails) {
43-
return Jwts.builder().setClaims(extraClaims).setSubject(userDetails.getUsername())
44-
.setIssuedAt(new Date(System.currentTimeMillis()))
45-
.setExpiration(new Date(System.currentTimeMillis() + 100000 * 60 * 24))
46-
.signWith(getSigningKey(), SignatureAlgorithm.HS256).compact();
50+
return Jwts.builder().claims(extraClaims).subject(userDetails.getUsername()).issuedAt(new Date(System.currentTimeMillis()))
51+
.expiration(new Date(System.currentTimeMillis() + 100000 * 60 * 24))
52+
.signWith(getSigningKey()).compact();
4753
}
4854

4955
public boolean isTokenValid(String token, UserDetails userDetails) {

0 commit comments

Comments
 (0)