使用Postman测试Spring代码时出现404及Forbidden错误求助
问题:Postman测试Spring项目时出现404与Forbidden错误
使用Postman测试Java Spring项目时,遇到404(资源未找到)和Forbidden(禁止访问)错误,以下是项目的Main Controller和Spring Security配置代码,请求协助排查问题。
Main Controller代码
package com.auto.website.controllers; import java.security.Principal; import java.util.Date; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import jakarta.validation.Valid; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import com.auto.website.models.User; import com.auto.website.services.UserService; import com.auto.website.Validator.UserValidator; @Controller public class MainController { private UserService userService; private UserValidator userValidator; public MainController(UserService userService, UserValidator userValidator) { this.userService = userService; this.userValidator = userValidator; } @RequestMapping("/register") public String registration( @Valid @ModelAttribute("user") User user, BindingResult result, Model model, HttpSession session, HttpServletRequest request) { userValidator.validate(user, result); // Store the password before it is encrypted String password = user.getPassword(); if(result.hasErrors()) { return "loginPage.jsp"; } // Make first user SUPER ADMIN if(userService.allUsers().size()==0) { userService.newUser(user, "ROLE_SUPER_ADMIN"); }else { userService.newUser(user, "ROLE_USER"); } // Log in new user with the password we stored before encrypting it authWithHttpServletRequest(request, user.getEmail(), password); return "redirect:/"; } // We will call this method to automatically log in newly registered users public void authWithHttpServletRequest(HttpServletRequest request, String email, String password) { try { request.login(email, password); } catch (ServletException e) { System.out.println("Error while login: " + e); } } @RequestMapping("/admin/{id}") public String makeAdmin(Principal principal, @PathVariable("id") Long id, Model model) { if(principal==null) { return "redirect:/login"; } User user = userService.findById(id); userService.upgradeUser(user); model.addAttribute("users", userService.allUsers()); return "redirect:/home"; } @RequestMapping("/login") public String login( @ModelAttribute("user") User user, @RequestParam(value="error", required=false) String error, @RequestParam(value="logout", required=false) String logout, Model model) { if(error!=null) { model.addAttribute("errorMessage","Invalid Credentials, Please try again."); } if(logout!=null) { model.addAttribute("logoutMessage","Logout Successful!"); } return "loginPage.jsp"; } @RequestMapping(value={"/", "/home"}) public String home(Principal principal, Model model) { if(principal==null) { return "redirect:/login"; } String email = principal.getName(); User user = userService.findByEmail(email); model.addAttribute("user", user); if(user!=null) { user.setLastLogin(new Date()); userService.updateUser(user); // If the user is an ADMIN or SUPER_ADMIN they will be redirected to the admin page if(user.getRoles().get(0).getName().contains("ROLE_SUPER_ADMIN")||user.getRoles().get(0).getName().contains("ROLE_ADMIN")) { model.addAttribute("currentUser", userService.findByEmail(email)); model.addAttribute("users", userService.allUsers()); return "adminPage.jsp"; } // All other users are redirected to the home page } return "home.jsp"; } @RequestMapping("/delete/{id}") public String deleteUser(Principal principal, @PathVariable("id") Long id, HttpSession session, Model model) { if(principal==null) { return "redirect:/login"; } User user = userService.findById(id); userService.deleteUser(user); model.addAttribute("users", userService.allUsers()); return "redirect:/home"; } }
Spring Security配置代码
package com.auto.website.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; @Configuration public class WebSecurityConfig { private UserDetailsService userDetailsService; @Autowired HandlerMappingIntrospector introspector; @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Bean protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ http .authorizeHttpRequests( auth -> auth.requestMatchers( new MvcRequestMatcher(introspector, "/css/**"), new MvcRequestMatcher(introspector, "/js/**"), new MvcRequestMatcher(introspector, "/register"), new MvcRequestMatcher(introspector, "/login") ).permitAll() .requestMatchers( new MvcRequestMatcher(introspector, "/delete/"), new MvcRequestMatcher(introspector, "/admin/**") ).hasAnyRole("SUPER_ADMIN", "ADMIN") .requestMatchers(new MvcRequestMatcher(introspector, "/home")).authenticated() .anyRequest().permitAll() ) .formLogin( form -> form.loginPage("/login") .usernameParameter("email") // Use email instead of userName for login purposes .permitAll() ) .logout( logout -> logout.permitAll() ); return http.build(); } public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); } }
排查要点
针对404错误
- 请求方法不匹配:控制器中所有
@RequestMapping未指定请求方法(如POST/GET),默认仅支持GET请求。若Postman发送POST请求到/register等端点,会因方法不匹配返回404。需为/register添加method = RequestMethod.POST,或用@PostMapping替代@RequestMapping。 - 路径匹配错误:Security配置中
/delete/的匹配规则未覆盖/delete/{id}路径,导致请求/delete/1时无法匹配到对应规则,需改为new MvcRequestMatcher(introspector, "/delete/**")。 - 视图解析配置:若测试返回jsp的端点(如
/home),需确保Spring MVC的视图解析器正确配置了前缀(如/WEB-INF/views/)和后缀(.jsp),否则会找不到视图文件返回404。
针对Forbidden错误
- 权限规则匹配问题:Security中
/delete/规则未覆盖实际请求路径/delete/{id},导致该请求会走anyRequest().permitAll(),但控制器内通过Principal判断未登录用户会重定向到/login,Postman中若未携带登录凭证,会因重定向或权限不足返回Forbidden。需修正Security中的/delete/为/delete/**。 - 角色权限不匹配:确认用户角色是否正确存储:控制器中创建用户时添加的是
ROLE_SUPER_ADMIN/ROLE_ADMIN,而Security的hasAnyRole("SUPER_ADMIN", "ADMIN")会自动添加ROLE_前缀,规则本身是正确的,但需验证用户实际拥有的角色是否符合要求。 - 自动登录失败:注册后的
authWithHttpServletRequest方法若调用request.login失败(如密码加密后不匹配),用户未完成登录,访问/home等需认证的端点会被重定向到/login,Postman中可能表现为Forbidden或302重定向。可添加日志排查该方法是否抛出异常。
内容的提问来源于stack exchange,提问作者chebbi ayoub
相关产品推荐
相关产品推荐

