updates
This commit is contained in:
@@ -9,6 +9,8 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import com.walkguide.security.JwtAuthFilter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
@@ -20,27 +22,28 @@ public class SecurityConfig {
|
||||
}
|
||||
|
||||
// Aturan jalan masuk ke API kita:
|
||||
// Jangan lupa inject filter-nya di atas (tambahin parameter JwtAuthFilter jwtAuthFilter)
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
public SecurityFilterChain filterChain(HttpSecurity http, JwtAuthFilter jwtAuthFilter) throws Exception {
|
||||
http
|
||||
.cors(cors -> cors.configurationSource(request -> {
|
||||
var corsConfiguration = new org.springframework.web.cors.CorsConfiguration();
|
||||
// Izinkan semua origin localhost dan semua port (biar Chrome gak ngeblok)
|
||||
corsConfiguration.setAllowedOriginPatterns(java.util.List.of(
|
||||
"http://localhost:*",
|
||||
"http://127.0.0.1:*"
|
||||
));
|
||||
corsConfiguration.setAllowedMethods(java.util.List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||
corsConfiguration.setAllowedHeaders(java.util.List.of("*"));
|
||||
corsConfiguration.setAllowCredentials(true);
|
||||
return corsConfiguration;
|
||||
var corsConfig = new org.springframework.web.cors.CorsConfiguration();
|
||||
corsConfig.setAllowedOriginPatterns(java.util.List.of("http://localhost:*", "http://127.0.0.1:*"));
|
||||
corsConfig.setAllowedMethods(java.util.List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||
corsConfig.setAllowedHeaders(java.util.List.of("*"));
|
||||
corsConfig.setAllowCredentials(true);
|
||||
return corsConfig;
|
||||
}))
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/api/auth/**").permitAll()
|
||||
.requestMatchers("/api/auth/**", "/swagger-ui/**", "/v3/api-docs/**").permitAll() // Login & Swagger bebas
|
||||
.requestMatchers("/api/guardian/**").hasRole("GUARDIAN") // Khusus Guardian
|
||||
.requestMatchers("/api/user/**").hasRole("USER") // Khusus Tunanetra
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
)
|
||||
// TARUH SATPAM DI SINI
|
||||
.addFilterBefore(jwtAuthFilter, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.walkguide.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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 com.walkguide.dto.ApiResponse;
|
||||
import com.walkguide.service.MockDataService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/guardian")
|
||||
@RequiredArgsConstructor
|
||||
public class GuardianController {
|
||||
|
||||
private final MockDataService mockDataService;
|
||||
|
||||
// 4. Ambil Status User
|
||||
@GetMapping("/user-status")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getUserStatus() {
|
||||
return ResponseEntity.ok(new ApiResponse<>(true, mockDataService.getUserStatus(), "Data status user berhasil diambil"));
|
||||
}
|
||||
|
||||
// 5. Setting Hardware Shortcut
|
||||
@PutMapping("/settings/shortcuts")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateShortcuts(@RequestBody Map<String, Object> request) {
|
||||
Map<String, Object> updated = mockDataService.updateShortcuts(request);
|
||||
return ResponseEntity.ok(new ApiResponse<>(true, updated, "Shortcut berhasil diperbarui"));
|
||||
}
|
||||
|
||||
// 6. Setting Sensitivitas AI
|
||||
@PutMapping("/settings/ai")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateAiSettings(@RequestBody Map<String, Object> request) {
|
||||
Map<String, Object> updated = mockDataService.updateAiSettings(request);
|
||||
return ResponseEntity.ok(new ApiResponse<>(true, updated, "Setting AI berhasil diperbarui"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.walkguide.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.walkguide.dto.ApiResponse;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/user")
|
||||
public class UserController {
|
||||
|
||||
// 7. Sinyal Darurat (Voice Command)
|
||||
@PostMapping("/emergency")
|
||||
public ResponseEntity<ApiResponse<String>> triggerEmergency(@RequestBody Map<String, Object> request) {
|
||||
// Simulasi mengirim notif ke Guardian
|
||||
String triggerType = (String) request.get("triggerType");
|
||||
return ResponseEntity.ok(new ApiResponse<>(true, "Darurat Terkirim", "Guardian telah diberi peringatan via: " + triggerType));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.walkguide.security;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class JwtAuthFilter extends OncePerRequestFilter {
|
||||
|
||||
private final JwtUtil jwtUtil;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
final String authHeader = request.getHeader("Authorization");
|
||||
|
||||
// Kalau gak ada token, lewatin aja (biar dicegat sama SecurityConfig)
|
||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// Potong tulisan "Bearer "
|
||||
final String jwt = authHeader.substring(7);
|
||||
|
||||
try {
|
||||
// Ambil email & role dari token lu
|
||||
String email = jwtUtil.extractUsername(jwt);
|
||||
String role = jwtUtil.extractRole(jwt); // Pastiin JwtUtil lu punya fungsi extractRole!
|
||||
|
||||
// Daftarin user ini ke sistem keamanan Spring
|
||||
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
||||
email, null, Collections.singletonList(new SimpleGrantedAuthority(role))
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(authToken);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Token kadaluarsa / rusak
|
||||
System.out.println("JWT Error: " + e.getMessage());
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
@@ -2,33 +2,67 @@ package com.walkguide.security;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
|
||||
@Component
|
||||
public class JwtUtil {
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String secret;
|
||||
// Kunci rahasia buat enkripsi & dekripsi token (Minimal 256-bit)
|
||||
private static final String SECRET_KEY = "404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970";
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private Long expiration;
|
||||
|
||||
private Key getSigningKey() {
|
||||
return Keys.hmacShaKeyFor(secret.getBytes());
|
||||
// Fungsi tambahan buat ngebongkar Email (Username)
|
||||
public String extractUsername(String token) {
|
||||
return extractClaim(token, Claims::getSubject);
|
||||
}
|
||||
|
||||
// Fungsi tambahan buat ngebongkar Role
|
||||
public String extractRole(String token) {
|
||||
Claims claims = extractAllClaims(token);
|
||||
return claims.get("role", String.class);
|
||||
}
|
||||
|
||||
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
|
||||
final Claims claims = extractAllClaims(token);
|
||||
return claimsResolver.apply(claims);
|
||||
}
|
||||
|
||||
private Claims extractAllClaims(String token) {
|
||||
return Jwts.parserBuilder()
|
||||
.setSigningKey(getSignInKey())
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
private Key getSignInKey() {
|
||||
byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
|
||||
return Keys.hmacShaKeyFor(keyBytes);
|
||||
}
|
||||
|
||||
// Fungsi lama lu buat bikin token
|
||||
public String generateToken(String email, String role) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("role", role);
|
||||
return createToken(claims, email);
|
||||
}
|
||||
|
||||
private String createToken(Map<String, Object> claims, String subject) {
|
||||
return Jwts.builder()
|
||||
.setSubject(email)
|
||||
.claim("role", role)
|
||||
.setClaims(claims)
|
||||
.setSubject(subject)
|
||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||
.setExpiration(new Date(System.currentTimeMillis() + expiration))
|
||||
.signWith(getSigningKey())
|
||||
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // Aktif 10 jam
|
||||
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
|
||||
.compact();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.walkguide.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MockDataService {
|
||||
|
||||
// Tambahin 'final' di sini sesuai saran VS Code
|
||||
private final Map<String, Object> userStatus = new HashMap<>();
|
||||
private final Map<String, Object> hardwareShortcuts = new HashMap<>();
|
||||
private final Map<String, Object> aiSettings = new HashMap<>();
|
||||
|
||||
public MockDataService() {
|
||||
// Data default awal saat Spring Boot nyala
|
||||
userStatus.put("status", "Sedang Berjalan");
|
||||
userStatus.put("location", "Jl. Kenangan, SBY");
|
||||
userStatus.put("batteryLevel", 85);
|
||||
userStatus.put("lastSeen", "2026-04-23T08:40:00Z");
|
||||
|
||||
hardwareShortcuts.put("volumeUpAction", "accept_call");
|
||||
hardwareShortcuts.put("volumeDownAction", "emergency_ping");
|
||||
|
||||
aiSettings.put("alertDistanceMeters", 2.5);
|
||||
aiSettings.put("hapticFeedback", true);
|
||||
}
|
||||
|
||||
public Map<String, Object> getUserStatus() {
|
||||
return userStatus;
|
||||
}
|
||||
|
||||
public Map<String, Object> updateShortcuts(Map<String, Object> newShortcuts) {
|
||||
hardwareShortcuts.putAll(newShortcuts);
|
||||
return hardwareShortcuts;
|
||||
}
|
||||
|
||||
public Map<String, Object> updateAiSettings(Map<String, Object> newSettings) {
|
||||
aiSettings.putAll(newSettings);
|
||||
return aiSettings;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user