HTTP 405不允许 - Spring Boot + Spring Security。

4

我是一名有用的助手,可以为您翻译文本。

我有一个简单的REST API,与数据库配合使用。在添加了安全性部分之前,它能够正常工作。现在在POST和DELETE请求时会返回HTTP 405 Not Allowed错误。我不知道原因。GET请求可以正常工作。

以下是控制器类:

@Controller
public class MarkerController {

    private Logger logger = Logger.getLogger(MarkerController.class.getName());

    @Autowired
    private MarkerServiceInterface markerService;

    @RequestMapping(value="/markers", method=RequestMethod.GET)
    public @ResponseBody List<Marker> getMarkers(@RequestParam(value="city", defaultValue="") String city) {
        logger.info("HANDLE GET REQUEST");



        return this.markerService.getAllMarkers();
    }

    @RequestMapping(value="/markers/new", method=RequestMethod.POST)
    public @ResponseBody Marker addMarker(@RequestBody Marker marker) {
        logger.info("HANDLE POST REQUEST");

        this.markerService.addMarker(marker);
        return marker;
    }

    @RequestMapping(value="/markers/delete", method=RequestMethod.DELETE)
    public @ResponseBody String deleteMarker(@RequestParam(value="id", defaultValue="") String id) {
        logger.info("HANDLE DELETE REQUEST");
        if (!id.equals("")) {
            logger.info(id);
            this.markerService.deleteMarker(Long.parseLong(id));
        }
        return "";
    }

    @RequestMapping(value="/admin/map")
    public String trafficSpy() {
        logger.info("HANDLE MAP");
        return "index";
    }

    @RequestMapping(value="/admin")
    public String admin() {
        return "admin";
    }

    @RequestMapping(value="/login")
    public String login() {
        return "login";
    }

}

This is the SecurityConfig:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    @Qualifier("userDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(
                passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http    
            .authorizeRequests()
            .antMatchers("/admin/**")
            .access("hasRole('ROLE_ADMIN')")
            .antMatchers("/markers/**")
            .access("hasRole('ROLE_USER')")
            .and()
            .formLogin()
            .loginPage("/login")
            .failureUrl("/login?error")
            .usernameParameter("username")
            .passwordParameter("password")
            .and()
            .logout()
            .logoutSuccessUrl("/login?logout")
            .and()
            .csrf()
            .and()
            .exceptionHandling()
            .accessDeniedPage("/403");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }

    @Bean
    public DaoAuthenticationProvider authProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }
}

DELETE请求是通过以下ajax代码调用的:
$.ajax({
        url: "localhost:8080/markers/delete?id=" + currentMarker.get("id"),
        type: 'DELETE',
        success: function(result) {
            console.log(result);
        }
    });

这是控制台中显示的消息:

2015-05-11 15:48:13.671  WARN 8279 --- [nio-8181-exec-6] o.s.web.servlet.PageNotFound             : Request method 'DELETE' not supported

这些是响应的头部信息。我可以看到在ALLOW中只有GET和HEAD。如果我没错的话,这意味着控制器中的方法仅接受GET和HEAD请求。

(Status-Line)               HTTP/1.1 405 Method Not Allowed
Server                      Apache-Coyote/1.1
x-content-type-options      nosniff
x-xss-protection            1; mode=block
Cache-Control               no-cache, no-store, max-age=0, must-revalidate
Pragma                      no-cache
Expires                     0
X-Frame-Options             DENY
Allow                       GET, HEAD
Content-Type                application/json;charset=UTF-8
Transfer-Encoding           chunked
Date                        Mon, 11 May 2015 17:35:31 GMT

在响应中,我遇到了这个异常:
org.springframework.web.HttpRequestMethodNotSupportedException

有什么想法是什么原因导致这个问题?我该如何允许POST和DELETE方法?

你是如何调用delete的?能否把代码粘贴出来?你不需要给""设置默认值,只需检查即可。我建议删除RequestMethod.Delete参数本身。 - We are Borg
为什么你没有删除RequestMethod.delete和默认值?另外,在你的function(result)中,你应该进行重定向。请不要返回“”,如果你想返回空,请将返回类型声明为void。为什么不尝试使用一个简单的控制器方法并直接从JSP/HTML调用它,而不是在AJAX上胡闹呢? - We are Borg
删除请求参数并没有解决任何问题。删除RequestMethod.DELETE也没有。我认为问题不在那里,因为在添加安全性之前代码运行良好。我的客户端不仅是jsp页面,还有一个Android客户端。 - dephinera
请澄清一下:如果您删除HTTP安全性,POSTDELETE就会成功吗? - Dirk Lachowski
我认为您缺少了 csrf 令牌。请您检查一下错误信息是否有相关提示。 - Manu Zi
显示剩余3条评论
3个回答

3

您忘记了 csrf 令牌。

建议您在 meta 标签中添加 csrf 令牌。您可以在 Spring Security 文档中阅读有关此令牌的信息。

通过这样做,您可以执行以下操作:

$(function () {
  var token = $("meta[name='_csrf']").attr("content");
  var header = $("meta[name='_csrf_header']").attr("content");
  $(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
  });
});

1
我想提供另一种解决方案,因为尽管Manu Zi的答案是正确的,但当我第一次遇到此问题并找到这个答案时,其中的根本问题并不立即清楚。这个问题的根源被405 Method Not Allowed的直接问题所掩盖。
在我的情况下,有两个因素起作用。首先,我的AccessDenied控制器没有POST方法,当拒绝POST方法并重定向到AccessDenied控制器时会导致405。只有在打开org.springframework.web的调试日志后才能看出来。
一旦这一点清楚了,就是弄清楚为什么我被拒绝访问的问题。所有权限和角色都是正确的,但由于从Spring 3升级到4,我发现CSRF保护默认启用。它需要被禁用,或者您必须使用Manu Zi的解决方案。
要禁用它,请参见: spring security 4 csrf disable via xml

0
在我的情况下,协议必须是 https 而不是 http

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接