This commit is contained in:
Chester.X 2024-07-02 16:40:45 +08:00
parent 4f132490c6
commit 94a7b1bc13
13 changed files with 245 additions and 78 deletions

21
pom.xml
View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -50,10 +50,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<!-- <dependency>--> <dependency>
<!-- <groupId>org.springframework.boot</groupId>--> <groupId>org.springframework.boot</groupId>
<!-- <artifactId>spring-boot-starter-security</artifactId>--> <artifactId>spring-boot-starter-security</artifactId>
<!-- </dependency>--> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
@ -62,27 +62,16 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId> <artifactId>spring-boot-starter-web-services</artifactId>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
<!-- <version>3.0.3</version>-->
<!-- </dependency>-->
<dependency> <dependency>
<groupId>org.springframework.session</groupId> <groupId>org.springframework.session</groupId>
<artifactId>spring-session-jdbc</artifactId> <artifactId>spring-session-jdbc</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId> <artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>com.h2database</groupId>-->
<!-- <artifactId>h2</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>

View File

@ -1,5 +1,4 @@
package org.cmh.backend.Config; package org.cmh.backend.Config;
// CorsConfig.java
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -14,8 +13,8 @@ public class CorsConfig {
return new WebMvcConfigurer() { return new WebMvcConfigurer() {
@Override @Override
public void addCorsMappings(CorsRegistry registry) { public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") registry.addMapping("/api/**")
.allowedOrigins("http://localhost:8080") .allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*") .allowedHeaders("*")
.allowCredentials(true); .allowCredentials(true);
@ -23,4 +22,3 @@ public class CorsConfig {
}; };
} }
} }

View File

@ -0,0 +1,54 @@
package org.cmh.backend.Config;
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.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.List;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/api/auth/register", "/api/auth/login").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
@Bean
public UrlBasedCorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(List.of("http://localhost:3000"));
config.setAllowedHeaders(List.of("*"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
source.registerCorsConfiguration("/**", config);
return source;
}
@Bean
public CorsFilter corsFilter() {
return new CorsFilter(corsConfigurationSource());
}
}

View File

@ -1,13 +1,45 @@
package org.cmh.backend.authentication.controller; package org.cmh.backend.authentication.controller;
import org.cmh.backend.authentication.model.User;
import org.cmh.backend.authentication.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping; import java.util.HashMap;
import org.springframework.web.bind.annotation.RestController; import java.util.Map;
@RestController @RestController
class AuthenticationController { @RequestMapping("/api/auth")
public class AuthenticationController {
@Autowired
private UserService userService;
@PostMapping("/register")
public User register(@RequestBody User user) {
return userService.register(user);
}
@PostMapping("/login")
public ResponseEntity<Map<String, Object>> login(@RequestBody User loginRequest) {
User user = userService.login(loginRequest.getUsername(), loginRequest.getPassword());
if (user == null) {
throw new RuntimeException("Invalid username or password");
}
Map<String, Object> response = new HashMap<>();
response.put("userId", user.getId());
response.put("user", user);
return ResponseEntity.ok(response);
}
@GetMapping("/hello") @GetMapping("/hello")
public String hello(){ public String hello(){
return "Hello SpringBoot!"; return "Hello SpringBoot!";
} }
@PostMapping("/getVerificationCode")
public String getVerificationCode(@RequestBody String contact) {
return "Verification code sent to " + contact;
}
} }

View File

@ -4,20 +4,52 @@ import org.cmh.backend.authentication.model.User;
import org.cmh.backend.authentication.service.UserService; import org.cmh.backend.authentication.service.UserService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("/users") @RequestMapping("/users")
public class UserController { public class UserController {
@Autowired @Autowired
private UserService userService; private UserService userService;
@GetMapping("/{username}") @CrossOrigin(origins = "http://localhost:3000")
public ResponseEntity<User> getUser(@PathVariable String username) { @PostMapping("/register")
User user = userService.getUserByUsername(username); public ResponseEntity<User> register(@RequestBody User user) {
return ResponseEntity.ok(user); User registeredUser = userService.register(user);
return ResponseEntity.ok(registeredUser);
}
@PostMapping("/login")
public ResponseEntity<User> login(@RequestParam String username, @RequestParam String password) {
User user = userService.login(username, password);
if (user != null) {
return ResponseEntity.ok(user);
}
return ResponseEntity.status(401).build();
}
@PutMapping("/update")
public ResponseEntity<User> updateUserInfo(@RequestBody User user) {
User updatedUser = userService.updateUserInfo(user);
return ResponseEntity.ok(updatedUser);
}
@PutMapping("/changePassword")
public ResponseEntity<?> changePassword(@RequestParam Long userId, @RequestParam String oldPassword, @RequestParam String newPassword) {
boolean isChanged = userService.changePassword(userId, oldPassword, newPassword);
if (isChanged) {
return ResponseEntity.ok("Password changed successfully");
}
return ResponseEntity.status(400).body("Old password is incorrect");
}
@GetMapping("/{userId}")
public ResponseEntity<User> getUserInfo(@PathVariable Long userId) {
User user = userService.findById(userId).orElse(null);
if (user != null) {
return ResponseEntity.ok(user);
}
return ResponseEntity.status(404).build();
} }
} }

View File

@ -1,39 +1,34 @@
// User.java
package org.cmh.backend.authentication.model; package org.cmh.backend.authentication.model;
import jakarta.persistence.Entity; import lombok.Data;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Data
@Entity @Entity
@Table(name = "Chester")
public class User { public class User {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
@Column(nullable = false, unique = true)
private String username; private String username;
@Column(nullable = false)
private String password; private String password;
public Long getId() { @Column(nullable = false)
return id; private String email;
}
public void setId(Long id) { @Column(nullable = false)
this.id = id; private String role;
}
public String getUsername() { private String phoneNumber;
return username; private String company;
}
public void setUsername(String username) { @Column(nullable = false)
this.username = username; private LocalDateTime createdDate;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
} }

View File

@ -2,7 +2,13 @@ package org.cmh.backend.authentication.repository;
import org.cmh.backend.authentication.model.User; import org.cmh.backend.authentication.model.User;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> { public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username); User findByUsername(String username);
Optional<User> findById(Long id);
User save(User user);
} }

View File

@ -1,16 +1,14 @@
package org.cmh.backend.authentication.service; package org.cmh.backend.authentication.service;
import org.cmh.backend.authentication.model.User; import org.cmh.backend.authentication.model.User;
import org.cmh.backend.authentication.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service import java.util.Optional;
public class UserService {
@Autowired
private UserRepository userRepository;
public User getUserByUsername(String username) { // UserService.java
return userRepository.findByUsername(username); public interface UserService {
} User register(User user);
User login(String username, String password);
User updateUserInfo(User user);
boolean changePassword(Long userId, String oldPassword, String newPassword);
Optional<User> findById(Long id);
} }

View File

@ -0,0 +1,58 @@
package org.cmh.backend.authentication.service;
import org.cmh.backend.authentication.model.User;
import org.cmh.backend.authentication.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Optional;
// UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public User register(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setCreatedDate(LocalDateTime.now());
return userRepository.save(user);
}
@Override
public User login(String username, String password) {
User user = userRepository.findByUsername(username);
if (user != null && passwordEncoder.matches(password, user.getPassword())) {
return user;
}
return null;
}
@Override
public User updateUserInfo(User user) {
return userRepository.save(user);
}
@Override
public boolean changePassword(Long userId, String oldPassword, String newPassword) {
User user = userRepository.findById(userId).orElse(null);
if (user != null && passwordEncoder.matches(oldPassword, user.getPassword())) {
user.setPassword(passwordEncoder.encode(newPassword));
userRepository.save(user);
return true;
}
return false;
}
@Override
public Optional<User> findById(Long id) {
return userRepository.findById(id);
}
}

View File

@ -0,0 +1,7 @@
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true

View File

@ -2,14 +2,11 @@ package org.cmh.backend;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
@Import(TestcontainersConfiguration.class)
@SpringBootTest @SpringBootTest
class BackendApplicationTests { public class BackendApplicationTests {
@Test @Test
void contextLoads() { void contextLoads() {
} }
} }

View File

@ -1,11 +1,12 @@
package org.cmh.backend; package org.cmh.backend;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TestBackendApplication { public class TestBackendApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.from(BackendApplication::main).with(TestcontainersConfiguration.class).run(args); SpringApplication.run(TestBackendApplication.class, args);
} }
} }