Spring Boot与React同端口部署访问localhost:8080返回403错误咨询
问题描述
我参照教程配置将React前端与Spring Boot后端部署在同一端口,期望启动Spring Boot应用后可通过localhost:8080访问站点。
当前遇到问题:访问localhost:8080时返回白标错误页(HTTP 403)。我的项目结构如下:
我尝试将应用主类以外的所有包移至com.websitePetcare目录下后,可以正常访问localhost:8080站点,但所有RestController无法被识别,接口无法正常调用。请问如何在保留现有可正常运行的项目结构前提下,实现localhost:8080可正常访问站点且接口可用?
项目相关配置代码
1. config包下的WebSecurity配置
package com.websitePetcare.Petcare.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import com.websitePetcare.Petcare.services.AuthenticationFilter; import com.websitePetcare.Petcare.services.LoginFilter; import com.websitePetcare.Petcare.services.UserDetailsServiceImpl; import java.util.List; @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl customUserDetailsService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type")); corsConfiguration.setAllowedOrigins(List.of("*")); corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE")); corsConfiguration.setAllowCredentials(true); corsConfiguration.setExposedHeaders(List.of("Authorization")); http.csrf().disable().cors().configurationSource(request -> corsConfiguration).and().authorizeRequests() .antMatchers(HttpMethod.POST, "/api/v1/users/login").permitAll() .antMatchers(HttpMethod.POST, "/api/v1/users/create").permitAll() .anyRequest().authenticated() .and() .addFilterBefore(new LoginFilter("/api/v1/users/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder()); } }
2. controllers包下的UsersController代码
package com.websitePetcare.Petcare.controllers; import com.websitePetcare.Petcare.repositories.UserRepository; import com.websitePetcare.Petcare.models.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import java.util.List; @RestController @RequestMapping("/api/v1") @CrossOrigin(origins = "http://localhost:8080") public class UsersController { @Autowired private UserRepository userRepository; @GetMapping("/") public ModelAndView home() { ModelAndView mav=new ModelAndView("index"); return mav; } @GetMapping("/users") @ResponseStatus(HttpStatus.OK) public List<User> list() { return userRepository.findAll(); } @PostMapping(value="/users/create") @ResponseStatus(HttpStatus.OK) public void create(@RequestBody User user) { userRepository.save(user); } }
3. 启动类PetcareApplication代码
package com.websitePetcare.Petcare; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; @SpringBootApplication(exclude = {SecurityAutoConfiguration.class}) public class PetcareApplication { public static void main(String[] args) { SpringApplication.run(PetcareApplication.class, args); } }
4. pom.xml配置
<?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" 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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.websitePetcare</groupId> <artifactId>Petcare</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Petcare</name> <description>Backend and Frontend for Petcare Website</description> <properties> <java.version>17</java.version> <frontend-src-dir>${project.basedir}/src/main/frontend</frontend-src-dir> <node.version>v16.13.0</node.version> <yarn.version>v1.22.17</yarn.version> <frontend-maven-plugin.version>1.12.0</frontend-maven-plugin.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.6.0</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.6.0</version> </dependency> <dependency> <groupId>commons-configuration</groupId> <artifactId>commons-configuration</artifactId> <version>1.9</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> <plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>${frontend-maven-plugin.version}</version> <configuration> <nodeVersion>${node.version}</nodeVersion> <yarnVersion>${yarn.version}</yarnVersion> <workingDirectory>${frontend-src-dir}</workingDirectory> <installDirectory>${project.build.directory}</installDirectory> </configuration> <executions> <execution> <id>install-frontend-tools</id> <goals> <goal>install-node-and-yarn</goal> </goals> </execution> <execution> <id>yarn-install</id> <goals> <goal>yarn</goal> </goals> <configuration> <arguments>install</arguments> </configuration> </execution> <execution> <id>build-frontend</id> <goals> <goal>yarn</goal> </goals> <phase>prepare-package</phase> <configuration> <arguments>build</arguments> </configuration> </execution> </executions> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>position-react-build</id> <goals> <goal>copy-resources</goal> </goals> <phase>prepare-package</phase> <configuration> <outputDirectory>${project.build.outputDirectory}/static</outputDirectory> <resources> <resource> <directory>${frontend-src-dir}/build</directory> <filtering>false</filtering> </resource> </resources> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
5. application.properties配置
spring.datasource.url=jdbc:postgresql://localhost:5432/websitepetcare spring.datasource.username=postgres spring.datasource.password=******* spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false spring.jpa.properties.hibernate.globally_quoted_identifiers=true # Because detection is disabled you have to set correct dialect by hand. spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect # Hibernate ddl auto (create, create-drop, validate, update) spring.jpa.hibernate.ddl-auto = update spring.thymeleaf.prefix=file:///${user.dir}/target/classes/static/
解决方案
按以下步骤修改即可同时满足页面正常访问、接口正常调用:
- 修复403访问错误:当前安全配置仅放开了登录注册接口,React打包后的静态资源、根路径默认需要登录权限,在WebSecurityConfig的
configure方法中新增静态资源放行规则:
http.csrf().disable().cors().configurationSource(request -> corsConfiguration).and().authorizeRequests() // 新增如下放行规则 .antMatchers("/", "/index.html", "/static/**", "/*.js", "/*.css", "/*.png", "/*.ico").permitAll() .antMatchers(HttpMethod.POST, "/api/v1/users/login").permitAll() .antMatchers(HttpMethod.POST, "/api/v1/users/create").permitAll() .anyRequest().authenticated() // 后续原有配置保持不变
- 修复包扫描冲突:启动类排除了
SecurityAutoConfiguration.class但自定义了带@EnableWebSecurity的安全配置类,两者存在冲突,修改启动类注解,移除exclude属性:
@SpringBootApplication
如果你需要将代码包放在上层com.websitePetcare目录下,在注解中指定扫描范围即可解决接口不识别的问题:
@SpringBootApplication(scanBasePackages = "com.websitePetcare")
- 可选优化:Spring Boot默认会读取static目录下的index.html作为根路径返回,可直接删除UsersController中的
home()方法,同时删掉application.properties中的spring.thymeleaf.prefix配置,无需额外通过接口返回首页。
内容的提问来源于stack exchange,提问作者BlowLore
相关产品推荐
相关产品推荐

