Added users logic to the NoteService
Fix password leak by introducing NoteResponse DTO Fix typo: "serurity" → "security"
This commit is contained in:
@@ -5,7 +5,7 @@ import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.tokishu.note.serurity.JwtService;
|
||||
import net.tokishu.note.seсurity.JwtService;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
@@ -2,13 +2,13 @@ package net.tokishu.note.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.tokishu.note.dto.request.NoteRequest;
|
||||
import net.tokishu.note.model.Note;
|
||||
import net.tokishu.note.dto.response.NoteResponse;
|
||||
import net.tokishu.note.service.NoteService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -20,17 +20,17 @@ public class NotesController {
|
||||
private final NoteService noteService;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<?> getAll(){
|
||||
public ResponseEntity<List<NoteResponse>> getAll(){
|
||||
return ResponseEntity.ok(noteService.getAll());
|
||||
}
|
||||
|
||||
@GetMapping("/{uuid}")
|
||||
public Note find(@PathVariable UUID uuid){
|
||||
public NoteResponse find(@PathVariable UUID uuid){
|
||||
return noteService.find(uuid);
|
||||
}
|
||||
|
||||
@PostMapping()
|
||||
public ResponseEntity<?> add(@RequestBody NoteRequest note){
|
||||
public ResponseEntity<Map<String, String>> add(@RequestBody NoteRequest note){
|
||||
noteService.add(note);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(Map.of("message", "Note added"));
|
||||
}
|
||||
@@ -44,6 +44,6 @@ public class NotesController {
|
||||
@DeleteMapping("/{uuid}")
|
||||
public ResponseEntity<?> delete(@PathVariable UUID uuid){
|
||||
noteService.delete(uuid);
|
||||
return ResponseEntity.ok(Map.of(" message", "Note deleted"));
|
||||
return ResponseEntity.ok(Map.of("message", "Note deleted"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.tokishu.note.dto.response;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class NoteResponse {
|
||||
private UUID uuid;
|
||||
private String name;
|
||||
private String text;
|
||||
private String author;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import net.tokishu.note.dto.response.RegisterResponse;
|
||||
import net.tokishu.note.dto.response.RootResponse;
|
||||
import net.tokishu.note.model.User;
|
||||
import net.tokishu.note.repo.UserRepository;
|
||||
import net.tokishu.note.serurity.JwtService;
|
||||
import net.tokishu.note.serurity.PasswordService;
|
||||
import net.tokishu.note.seсurity.JwtService;
|
||||
import net.tokishu.note.seсurity.PasswordService;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -2,50 +2,101 @@ package net.tokishu.note.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.tokishu.note.dto.request.NoteRequest;
|
||||
import net.tokishu.note.dto.response.NoteResponse;
|
||||
import net.tokishu.note.model.Note;
|
||||
import net.tokishu.note.model.User;
|
||||
import net.tokishu.note.repo.NoteRepository;
|
||||
import net.tokishu.note.repo.UserRepository;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class NoteService {
|
||||
|
||||
public final NoteRepository noteRepository;
|
||||
public final UserService userService;
|
||||
public final UserRepository userRepository;
|
||||
|
||||
public List<Note> getAll(){
|
||||
return noteRepository.findAll();
|
||||
public List<NoteResponse> getAll() {
|
||||
User currentUser = userService.getCurrentUser();
|
||||
List<Note> notes;
|
||||
|
||||
if ("ADMIN".equalsIgnoreCase(currentUser.getRole())) {
|
||||
notes = noteRepository.findAll();
|
||||
} else {
|
||||
notes = noteRepository.findByAuthorUsername(currentUser.getUsername());
|
||||
}
|
||||
|
||||
return notes.stream()
|
||||
.map(this::toResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Note find(UUID uuid) {
|
||||
return noteRepository.findById(uuid)
|
||||
public NoteResponse find(UUID uuid) {
|
||||
Note note = noteRepository.findById(uuid)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Note not found"));
|
||||
|
||||
User currentUser = userService.getCurrentUser();
|
||||
checkOwnership(note, currentUser);
|
||||
return toResponse(note);
|
||||
}
|
||||
|
||||
public NoteResponse add(NoteRequest data){
|
||||
User author = userService.getCurrentUser();
|
||||
|
||||
public Note add(NoteRequest data){
|
||||
Note note = new Note();
|
||||
note.setName(data.getName());
|
||||
note.setText(data.getText());
|
||||
note.setName(data.getName());
|
||||
note.setText(data.getText());
|
||||
note.setAuthor(author);
|
||||
|
||||
return noteRepository.save(note);
|
||||
Note saved = noteRepository.save(note);
|
||||
return toResponse(saved);
|
||||
}
|
||||
|
||||
public Note update(UUID uuid, NoteRequest data){
|
||||
public NoteResponse update(UUID uuid, NoteRequest data) {
|
||||
Note existing = noteRepository.findById(uuid)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Note not found"));
|
||||
existing.setName(data.getName());
|
||||
existing.setText(data.getText());
|
||||
|
||||
return noteRepository.save(existing);
|
||||
User currentUser = userService.getCurrentUser();
|
||||
checkOwnership(existing, currentUser);
|
||||
|
||||
existing.setName(data.getName());
|
||||
existing.setText(data.getText());
|
||||
|
||||
return toResponse(noteRepository.save(existing));
|
||||
}
|
||||
|
||||
public void delete(UUID uuid){
|
||||
public void delete(UUID uuid) {
|
||||
Note existing = noteRepository.findById(uuid)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Note not found"));
|
||||
noteRepository.deleteById(uuid);
|
||||
|
||||
User currentUser = userService.getCurrentUser();
|
||||
checkOwnership(existing, currentUser);
|
||||
noteRepository.delete(existing);
|
||||
}
|
||||
|
||||
private void checkOwnership(Note note, User user) {
|
||||
if ("ADMIN".equalsIgnoreCase(user.getRole())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!note.getAuthor().getUsername().equals(user.getUsername())) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "You are not the author of this note");
|
||||
}
|
||||
}
|
||||
|
||||
private NoteResponse toResponse(Note note) {
|
||||
return NoteResponse.builder()
|
||||
.uuid(note.getUuid())
|
||||
.name(note.getName())
|
||||
.text(note.getText())
|
||||
.author(note.getAuthor().getUsername())
|
||||
.createdAt(note.getCreatedAt())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,13 @@ package net.tokishu.note.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.tokishu.note.dto.request.RegisterRequest;
|
||||
import net.tokishu.note.dto.response.UserResponse;
|
||||
import net.tokishu.note.model.User;
|
||||
import net.tokishu.note.repo.UserRepository;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
@@ -19,4 +23,35 @@ public class UserService {
|
||||
public List<User> getAll(){
|
||||
return userRepository.findAll();
|
||||
}
|
||||
|
||||
public User getCurrentUser() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (authentication == null || !authentication.isAuthenticated()) {
|
||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not authenticated");
|
||||
}
|
||||
|
||||
Object principal = authentication.getPrincipal();
|
||||
String username;
|
||||
|
||||
if (principal instanceof UserDetails userDetails) {
|
||||
username = userDetails.getUsername();
|
||||
} else if (principal instanceof String) {
|
||||
username = (String) principal;
|
||||
} else {
|
||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unable to identify user");
|
||||
}
|
||||
|
||||
return userRepository.findById(username)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found"));
|
||||
}
|
||||
|
||||
public UserResponse getCurrentUserResponse() {
|
||||
User user = getCurrentUser();
|
||||
return UserResponse.builder()
|
||||
.username(user.getUsername())
|
||||
.role(user.getRole())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package net.tokishu.note.serurity;
|
||||
package net.tokishu.note.seсurity;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.tokishu.note.model.User;
|
||||
+16
-7
@@ -1,13 +1,16 @@
|
||||
package net.tokishu.note.serurity;
|
||||
package net.tokishu.note.seсurity;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.Date;
|
||||
@@ -49,14 +52,20 @@ public class JwtService {
|
||||
return extractClaim(token, Claims::getExpiration);
|
||||
}
|
||||
|
||||
private Claims extractAllClaims(String token) {
|
||||
return Jwts.parser()
|
||||
.setSigningKey(getSignKey())
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
// JwtService.java
|
||||
public Claims extractAllClaims(String token) {
|
||||
try {
|
||||
return Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.build()
|
||||
.parseSignedClaims(token)
|
||||
.getPayload();
|
||||
} catch (ExpiredJwtException e) {
|
||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Token expired");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Key getSignKey() {
|
||||
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
|
||||
return Keys.hmacShaKeyFor(keyBytes);
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package net.tokishu.note.serurity;
|
||||
package net.tokishu.note.seсurity;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
Reference in New Issue
Block a user