Add a PortfolioController to retrieve all data relevant to portfolio (Other controllers) with authentication (api-key)

This commit is contained in:
Murtadha 2024-12-13 22:15:16 -05:00
parent e22d2b6fca
commit dccae4cad0
7 changed files with 145 additions and 30 deletions

14
pom.xml
View file

@ -71,6 +71,20 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>

View file

@ -0,0 +1,30 @@
package io.titan.portfolio.config;
import io.titan.portfolio.security.ApiKeyFilter;
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.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
private final ApiKeyFilter apiKeyFilter;
public SecurityConfig(ApiKeyFilter apiKeyFilter) {
this.apiKeyFilter = apiKeyFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // Disable CSRF for APIs
.addFilterBefore(apiKeyFilter, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/portfolio").authenticated() // Secure the endpoint
.anyRequest().permitAll() // Allow other requests
);
return http.build();
}
}

View file

@ -3,22 +3,14 @@ package io.titan.portfolio.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
// import org.springframework.web.bind.annotation.DeleteMapping;
// import org.springframework.web.bind.annotation.GetMapping;
// import org.springframework.web.bind.annotation.PathVariable;
// import org.springframework.web.bind.annotation.PostMapping;
// import org.springframework.web.bind.annotation.PutMapping;
// import org.springframework.web.bind.annotation.RequestBody;
// import org.springframework.web.bind.annotation.RequestMapping;
// import org.springframework.web.bind.annotation.RestController;
import io.titan.portfolio.model.Education;
import io.titan.portfolio.service.EducationService;
import java.util.List;
@RestController
@RequestMapping("/api/portfolio/education")
// @RestController
// @RequestMapping("/api/portfolio/education")
public class EducationController {
private final EducationService educationService;
@ -26,25 +18,25 @@ public class EducationController {
this.educationService = educationService;
}
@GetMapping
// @GetMapping
List<Education> getAllEducation(){
return educationService.getAllEducation();
}
@GetMapping("/{id}")
// @GetMapping("/{id}")
ResponseEntity<Education> getEducationById(@PathVariable String id) {
return educationService.getEducationById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
// @PostMapping
ResponseEntity<Void> createEducation(@RequestBody Education education) {
educationService.createEducation(education);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
@PutMapping("/{id}")
// @PutMapping("/{id}")
ResponseEntity<Education> updateEducation(@PathVariable String id, @RequestBody Education education) {
if (!id.equals(education.id())) {
return ResponseEntity.badRequest().build();
@ -53,7 +45,7 @@ public class EducationController {
return ResponseEntity.ok(education);
}
@DeleteMapping("/{id}")
// @DeleteMapping("/{id}")
ResponseEntity<Void> deleteEducation(@PathVariable String id) {
boolean deleted = educationService.deleteEducation(id);
return deleted ? ResponseEntity.ok().build() : ResponseEntity.notFound().build();

View file

@ -0,0 +1,39 @@
package io.titan.portfolio.controller;
import io.titan.portfolio.model.Education;
// import io.titan.portfolio.model.Experience;
import io.titan.portfolio.service.EducationService;
// import io.titan.portfolio.service.ExperienceService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
// import org.springframework.beans.factory.annotation.Value;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/portfolio")
public class PortfolioController {
private final EducationService educationService;
// @Value("${api.key}")
// private String apiKey;
PortfolioController(EducationService educationService){
this.educationService = educationService;
}
@GetMapping
public ResponseEntity<Map<String, Object>> getPortfolio() {
List<Education> educationList = educationService.getAllEducation();
// List<Experience> experienceList = experienceService.getAllExperience();
Map<String, Object> portfolio = Map.of(
"education", educationList
// "experience", experienceList
);
return ResponseEntity.ok(portfolio);
}
}

View file

@ -4,17 +4,6 @@ import io.titan.portfolio.model.Education;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
// import org.springframework.jdbc.core.JdbcTemplate;
// import org.springframework.jdbc.core.RowMapper;
// import org.springframework.jdbc.support.GeneratedKeyHolder;
// import org.springframework.jdbc.support.KeyHolder;
// import org.springframework.stereotype.Repository;
// import java.sql.PreparedStatement;
// import java.sql.Statement;
// import java.util.Arrays;
// import java.util.List;
// import java.util.Optional;
@Repository
public interface EducationRepository extends MongoRepository<Education, String>{

View file

@ -0,0 +1,39 @@
package io.titan.portfolio.security;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class ApiKeyFilter extends OncePerRequestFilter {
@Value("${api.key}")
private String apiKey;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String requestApiKey = request.getHeader("X-API-KEY");
if (apiKey.equals(requestApiKey)) {
Authentication auth = new PreAuthenticatedAuthenticationToken("apiKeyUser", null, null);
SecurityContextHolder.getContext().setAuthentication(auth);
} else {
response.sendError(HttpStatus.UNAUTHORIZED.value(), "Invalid API Key");
return;
}
filterChain.doFilter(request, response);
}
}

View file

@ -1,6 +1,18 @@
spring.data.mongodb.uri=mongodb://portfolio_user:portfolio_P%40ssword@localhost:27017/portfolio_db
spring.application.name=titan_backend
spring.devtools.restart.enabled=true
# spring.application.name=titan_backend
# spring.devtools.restart.enabled=true
# server.port=8282
# spring.data.mongodb.uri=${MONGO_URL}
# api.key=${API_KEY}
spring.profiles.active=dev
# # Logging level
# logging.level.root=INFO
# Development MongoDB connection
spring.data.mongodb.uri=mongodb://portfolio_user:portfolio_P%40ssword@localhost:27017/portfolio_db
# api.key=dev-api-key-12345
server.port=8282
# logging.level.root=DEBUG
# Logging Level
logging.level.root=DEBUG