I accidentally pushed into that branch :(

Added JWT
This commit is contained in:
Tokishu
2025-05-26 17:25:18 -07:00
committed by GitHub
30 changed files with 706 additions and 24 deletions
+33
View File
@@ -74,6 +74,39 @@
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId> <artifactId>spring-data-jpa</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.6</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>6.5.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@@ -0,0 +1,65 @@
package net.tokishu.note.config;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import net.tokishu.note.serurity.JwtService;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@RequiredArgsConstructor
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
final String jwt;
final String username;
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
jwt = authHeader.substring(7);
username = jwtService.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}
@@ -0,0 +1,46 @@
package net.tokishu.note.config;
import lombok.RequiredArgsConstructor;
import net.tokishu.note.exception.SecurityExceptionHandler;
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.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@RequiredArgsConstructor
@Configuration
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
private final SecurityExceptionHandler securityExceptionHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(securityExceptionHandler)
.accessDeniedHandler(securityExceptionHandler)
)
.authorizeHttpRequests(auth -> auth
.requestMatchers(new AntPathRequestMatcher("/api/auth/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/h2-console/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/error")).permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@@ -0,0 +1,47 @@
package net.tokishu.note.controller;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import net.tokishu.note.dto.request.LoginRequest;
import net.tokishu.note.dto.request.RegisterRequest;
import net.tokishu.note.dto.response.LoginResponse;
import net.tokishu.note.dto.response.RegisterResponse;
import net.tokishu.note.dto.response.RootResponse;
import net.tokishu.note.model.User;
import net.tokishu.note.service.AuthService;
import net.tokishu.note.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequiredArgsConstructor
@RequestMapping("/auth")
public class AuthController {
public final AuthService authService;
public final UserService userService;
@PostMapping("/register")
public ResponseEntity<RegisterResponse> register(@RequestBody @Valid RegisterRequest request) {
RegisterResponse response = authService.registerUser(request);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
@PostMapping("/login")
public ResponseEntity<LoginResponse> login(@RequestBody @Valid LoginRequest request) {
LoginResponse response = authService.authorizeUser(request);
return ResponseEntity.ok(response);
}
@PostMapping("/new-root")
public ResponseEntity<RootResponse> newRoot() {
RootResponse response = authService.registerRoot();
return ResponseEntity.ok(response);
}
}
@@ -1,6 +1,7 @@
package net.tokishu.note.controller; package net.tokishu.note.controller;
import net.tokishu.note.dto.NoteRequest; import lombok.RequiredArgsConstructor;
import net.tokishu.note.dto.request.NoteRequest;
import net.tokishu.note.model.Note; import net.tokishu.note.model.Note;
import net.tokishu.note.service.NoteService; import net.tokishu.note.service.NoteService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -8,40 +9,39 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@RequiredArgsConstructor
@RestController @RestController
@RequestMapping("/notes")
public class NotesController { public class NotesController {
@Autowired private final NoteService noteService;
private NoteService noteService;
@GetMapping("/notes") @GetMapping
public ResponseEntity<?> getAll(){ public ResponseEntity<?> getAll(){
return ResponseEntity.ok(noteService.getAll()); return ResponseEntity.ok(noteService.getAll());
} }
@GetMapping("/note/{uuid}") @GetMapping("/{uuid}")
public Note find(@PathVariable UUID uuid){ public Note find(@PathVariable UUID uuid){
return noteService.find(uuid); return noteService.find(uuid);
} }
@PostMapping("/note") @PostMapping()
public ResponseEntity<?> add(@RequestBody NoteRequest note){ public ResponseEntity<?> add(@RequestBody NoteRequest note){
noteService.add(note); noteService.add(note);
return ResponseEntity.status(HttpStatus.CREATED).body(Map.of("message", "Note added")); return ResponseEntity.status(HttpStatus.CREATED).body(Map.of("message", "Note added"));
} }
@PutMapping("/note/{uuid}") @PutMapping("/{uuid}")
public ResponseEntity<?> update(@PathVariable("uuid") UUID uuid, @RequestBody NoteRequest note){ public ResponseEntity<?> update(@PathVariable("uuid") UUID uuid, @RequestBody NoteRequest note){
noteService.update(uuid, note); noteService.update(uuid, note);
return ResponseEntity.ok(Map.of("message", "Note updated")); return ResponseEntity.ok(Map.of("message", "Note updated"));
} }
@DeleteMapping("/note/{uuid}") @DeleteMapping("/{uuid}")
public ResponseEntity<?> delete(@PathVariable UUID uuid){ public ResponseEntity<?> delete(@PathVariable UUID uuid){
noteService.delete(uuid); noteService.delete(uuid);
return ResponseEntity.ok(Map.of(" message", "Note deleted")); return ResponseEntity.ok(Map.of(" message", "Note deleted"));
@@ -0,0 +1,12 @@
package net.tokishu.note.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
@RequestMapping("/users")
public class UserController {
}
@@ -1,9 +0,0 @@
package net.tokishu.note.dto;
import lombok.Data;
@Data
public class NoteRequest {
private String name;
private String text;
}
@@ -0,0 +1,13 @@
package net.tokishu.note.dto.request;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class LoginRequest {
@NotBlank
private String username;
@NotBlank
private String password;
}
@@ -0,0 +1,16 @@
package net.tokishu.note.dto.request;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Data
public class NoteRequest {
@NotBlank
@Size(min=1, max=128)
private String name;
@NotBlank
@Size(min=1, max=8192)
private String text;
}
@@ -0,0 +1,16 @@
package net.tokishu.note.dto.request;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Data
public class RegisterRequest {
@NotBlank
@Size(min=1, max=24)
private String username;
@NotBlank
@Size(min=6, max=42)
private String password;
}
@@ -0,0 +1,5 @@
package net.tokishu.note.dto.request;
public class UserRequest {
}
@@ -0,0 +1,11 @@
package net.tokishu.note.dto.response;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class ApiErrorResponse {
private final int status;
private final String message;
}
@@ -0,0 +1,12 @@
package net.tokishu.note.dto.response;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class LoginResponse {
private String token;
private String username;
private String role;
}
@@ -0,0 +1,12 @@
package net.tokishu.note.dto.response;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class RegisterResponse {
private String username;
private String role;
private String message;
}
@@ -0,0 +1,12 @@
package net.tokishu.note.dto.response;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class RootResponse {
private String username;
private String password;
private String role;
}
@@ -0,0 +1,11 @@
package net.tokishu.note.dto.response;
import lombok.Data;
import lombok.Builder;
@Data
@Builder
public class UserResponse {
private String username;
private String role;
}
@@ -0,0 +1,59 @@
package net.tokishu.note.exception;
import jakarta.servlet.http.HttpServletRequest;
import net.tokishu.note.dto.response.ApiErrorResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.NoHandlerFoundException;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResponseStatusException.class)
public ResponseEntity<ApiErrorResponse> handle(ResponseStatusException ex) {
return ResponseEntity
.status(ex.getStatusCode())
.body(ApiErrorResponse.builder()
.status(ex.getStatusCode().value())
.message(ex.getReason() != null ? ex.getReason() : "Unexpected error")
.build()
);
}
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<ApiErrorResponse> handleBadRequest(HttpMessageNotReadableException ex) {
return ResponseEntity
.badRequest()
.body(ApiErrorResponse.builder()
.status(400)
.message("Invalid request body")
.build()
);
}
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<ApiErrorResponse> handleNotFound(NoHandlerFoundException ex) {
return ResponseEntity
.status(404)
.body(ApiErrorResponse.builder()
.status(404)
.message("Endpoint not found")
.build()
);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiErrorResponse> handleGeneric(Exception ex) {
return ResponseEntity
.status(500)
.body(ApiErrorResponse.builder()
.status(500)
.message("Internal server error")
.build()
);
}
}
@@ -0,0 +1,41 @@
package net.tokishu.note.exception;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.tokishu.note.dto.response.ApiErrorResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class SecurityExceptionHandler implements AuthenticationEntryPoint, AccessDeniedHandler {
private final ObjectMapper objectMapper = new ObjectMapper();
private void writeErrorResponse(HttpServletResponse response, int status, String message) throws IOException {
response.setStatus(status);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
ApiErrorResponse body = ApiErrorResponse.builder()
.status(status)
.message(message)
.build();
response.getWriter().write(objectMapper.writeValueAsString(body));
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
org.springframework.security.core.AuthenticationException authException) throws IOException {
writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
writeErrorResponse(response, HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}
@@ -2,8 +2,10 @@ package net.tokishu.note.model;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.Data; import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.UUID; import java.util.UUID;
@Entity @Entity
@@ -15,4 +17,12 @@ public class Note {
private UUID uuid; private UUID uuid;
private String name; private String name;
private String text; private String text;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author", referencedColumnName = "username")
private User author;
@CreationTimestamp
@Column(updatable = false)
private LocalDateTime createdAt;
} }
@@ -0,0 +1,25 @@
package net.tokishu.note.model;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import java.time.LocalDateTime;
import java.util.UUID;
@Entity
@Data
@Table(name = "Users")
public class User {
@Id
private String username;
private String password;
@ColumnDefault("'USER'")
private String role;
@CreationTimestamp
@Column(updatable = false)
private LocalDateTime createdAt;
}
@@ -1,8 +1,12 @@
package net.tokishu.note.repo; package net.tokishu.note.repo;
import net.tokishu.note.model.Note;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface NoteRepository extends JpaRepository<net.tokishu.note.model.Note, UUID> { public interface NoteRepository extends JpaRepository<Note, UUID> {
List<Note> findByAuthorUsername(String username);
List<Note> findByAuthorUsernameOrderByCreatedAtDesc(String username);
} }
@@ -0,0 +1,9 @@
package net.tokishu.note.repo;
import net.tokishu.note.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.UUID;
public interface UserRepository extends JpaRepository<User, String> {
}
@@ -0,0 +1,28 @@
package net.tokishu.note.serurity;
import lombok.RequiredArgsConstructor;
import net.tokishu.note.model.User;
import net.tokishu.note.repo.UserRepository;
import org.springframework.security.core.userdetails.*;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Collections;
@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findById(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + user.getRole()))
);
}
}
@@ -0,0 +1,64 @@
package net.tokishu.note.serurity;
import io.jsonwebtoken.Claims;
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.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.security.Key;
import java.util.Date;
import java.util.function.Function;
@Service
public class JwtService {
@Value("${jwt.secret}")
private String secretKey;
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)) // 24 hours
.signWith(getSignKey(), SignatureAlgorithm.HS256)
.compact();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
}
private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
private Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
private Claims extractAllClaims(String token) {
return Jwts.parser()
.setSigningKey(getSignKey())
.build()
.parseClaimsJws(token)
.getBody();
}
private Key getSignKey() {
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
return Keys.hmacShaKeyFor(keyBytes);
}
}
@@ -0,0 +1,20 @@
package net.tokishu.note.serurity;
import org.springframework.stereotype.Service;
import java.security.SecureRandom;
@Service
public class PasswordService {
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final SecureRandom RANDOM = new SecureRandom();
public String generate(int length) {
StringBuilder password = new StringBuilder();
for (int i = 0; i < length; i++) {
password.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length())));
}
return password.toString();
}
}
@@ -0,0 +1,93 @@
package net.tokishu.note.service;
import lombok.RequiredArgsConstructor;
import net.tokishu.note.dto.request.LoginRequest;
import net.tokishu.note.dto.request.RegisterRequest;
import net.tokishu.note.dto.response.LoginResponse;
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 org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
@Service
@RequiredArgsConstructor
public class AuthService {
public final UserRepository userRepository;
public final UserService userService;
public final PasswordService passwordService;
private final PasswordEncoder passwordEncoder;
private final JwtService jwtService;
public RootResponse registerRoot() {
userRepository.findById("root").ifPresent(user -> {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Root user already exists");
});
String rawPassword = passwordService.generate(16);
String hashedPassword = passwordEncoder.encode(rawPassword);
User rootUser = new User();
rootUser.setUsername("root");
rootUser.setPassword(hashedPassword);
rootUser.setRole("ADMIN");
userRepository.save(rootUser);
return RootResponse.builder()
.username(rootUser.getUsername())
.password(rawPassword)
.role(rootUser.getRole())
.build();
}
public RegisterResponse registerUser(RegisterRequest request) {
if (userRepository.existsById(request.getUsername())) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "User already exists");
}
User user = new User();
user.setUsername(request.getUsername());
user.setPassword(passwordEncoder.encode(request.getPassword()));
user.setRole("USER");
userRepository.save(user);
return RegisterResponse.builder()
.username(user.getUsername())
.role(user.getRole())
.message("Registration successful")
.build();
}
public LoginResponse authorizeUser(LoginRequest request) {
User user = userRepository.findById(request.getUsername())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"));
if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid credentials");
}
String token = jwtService.generateToken(
org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build()
);
return LoginResponse.builder()
.token(token)
.username(user.getUsername())
.role(user.getRole())
.build();
}
}
@@ -1,7 +1,7 @@
package net.tokishu.note.service; package net.tokishu.note.service;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.tokishu.note.dto.NoteRequest; import net.tokishu.note.dto.request.NoteRequest;
import net.tokishu.note.model.Note; import net.tokishu.note.model.Note;
import net.tokishu.note.repo.NoteRepository; import net.tokishu.note.repo.NoteRepository;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@@ -9,7 +9,6 @@ import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ResponseStatusException;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -0,0 +1,22 @@
package net.tokishu.note.service;
import lombok.RequiredArgsConstructor;
import net.tokishu.note.dto.request.RegisterRequest;
import net.tokishu.note.model.User;
import net.tokishu.note.repo.UserRepository;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.List;
@Service
@RequiredArgsConstructor
public class UserService {
public final UserRepository userRepository;
public List<User> getAll(){
return userRepository.findAll();
}
}
@@ -1,6 +1,10 @@
spring.application.name=notes spring.application.name=notes
spring.mvc.servlet.path=/api spring.mvc.servlet.path=/api
?Error
spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false
# DB # DB
spring.datasource.url=jdbc:postgresql://localhost:5432/notes spring.datasource.url=jdbc:postgresql://localhost:5432/notes
spring.datasource.username=postgres spring.datasource.username=postgres
@@ -9,3 +13,5 @@ spring.jpa.hibernate.ddl-auto=update
# Disable trace # Disable trace
server.error.include-stacktrace=never server.error.include-stacktrace=never
jwt.secret=f037435dc264ba72492096d3f3eb2f3da046f75ce45c85bc9bb487caa2bedb60
@@ -1,6 +1,6 @@
package net.tokishu.note.service; package net.tokishu.note.service;
import net.tokishu.note.dto.NoteRequest; import net.tokishu.note.dto.request.NoteRequest;
import net.tokishu.note.model.Note; import net.tokishu.note.model.Note;
import net.tokishu.note.repo.NoteRepository; import net.tokishu.note.repo.NoteRepository;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;