You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 10:05:58