http方法put

tyu7yeag  于 2021-07-23  发布在  Java
关注(0)|答案(0)|浏览(217)

早上好,我正在开发一个springboot(最新版本)应用程序,使用springsecurity(最新版本)进行保护。
我在试着做一个决定 PUT 从jsp页面向spring rest端点的请求,该端点只应返回 String 对象,尤其是:
jsp代码:在一个脚本中,我发出以下ajax请求

<!-- change event of batch status script -->
function changeEventStatus(idEvento, statoEvento) {
    let data = {"id_evento": idEvento, "stato": statoEvento};

    $.ajax({
        url: 'http://localhost:8080/entsorgafin/events/api/cambiaStatoEvento',
        type: 'PUT',
        contentType: 'application/json',
        data: JSON.stringify(data)
    }).then(function (data) {
        console.log("process terminated.");
        console.log("data collected:");
        console.log(data);
    });
}

控制器代码:控制器带有注解 @RestController 以及 @CrossOrigin 注解以支持cors请求和rest请求的spring自动管理

@PutMapping("/cambiaStatoEvento")
public String changeEventStatus(@RequestBody Evento evento)
{
    logger.info("API CONTROLLER - changing the status of the event with ID " + evento.getId_evento());

    //If the status status is not Risolto, the event will be taken in charge
    if(! evento.getStato().equals("Risolto"))
    {
        logger.info("API CONTROLLER - status of event " + evento.getId_evento() + " changed to In Lavorazione");
        eventoService.changeEventStatus(evento.getId_evento(), "In Lavorazione");
    } else
    {
        logger.info("API CONTROLLER - status of event " + evento.getId_evento() + " changed to Risolto");
        eventoService.changeEventStatus(evento.getId_evento(), "Risolto");
    }

    return "SUCCESS";
}

我使用chrome devtools进行了检查,有效负载被正确编码并发送,但是当我发出请求时,spring引导会记录以下内容:

2021-01-18 17:18:00.822 DEBUG 15564 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : "FORWARD" dispatch for PUT "/accessDenied", parameters={}
2021-01-18 17:18:00.827  WARN 15564 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'PUT' not supported]
2021-01-18 17:18:00.828 DEBUG 15564 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Exiting from "FORWARD" dispatch, status 405
2021-01-18 17:18:00.829 DEBUG 15564 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for PUT "/error", parameters={}
2021-01-18 17:18:00.830 DEBUG 15564 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2021-01-18 17:18:00.832 DEBUG 15564 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2021-01-18 17:18:00.832 DEBUG 15564 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Writing [{timestamp=Mon Jan 18 17:18:00 CET 2021, status=405, error=Method Not Allowed, trace=org.springframe (truncated)...]
2021-01-18 17:18:00.833 DEBUG 15564 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 405

说到这里,我试着 GET 请求并按预期工作正常 DELETE 以及 POST 请求不起作用 PUT 一个。
仅仅通过阅读日志,我认为这是一个spring安全问题,但我不明白我面临的问题是什么,我从spring文档中看到cors请求是自动管理的,不应该做任何事情,但它显然不是这样工作的。
如果有人能帮我解决我所缺少的问题,或者只是指出一些我能找到答案的地方,因为我真的不知道这里会出什么问题,提前谢谢。
编辑
安全配置

package com.entsorgafin.sr002EagleCloud.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
    //Dependency Injection
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Qualifier("securityUserDetailService")
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * Manages the encoder to save passwords in the DB
     * not in plain text
     *
     * @return PasswordEncoder object
     */
    @Bean
    public PasswordEncoder passwordEncoder()
    {
        return new BCryptPasswordEncoder();
    }

    /**
     * Manages the configuration of the Authentication manager with
     * user credentials and roles.
     * <p>
     * The AuthenticationManager processes any authentication request.
     *
     * @param auth AuthenticationManagerBuilder object
     */
    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth)
    {
        auth.authenticationProvider(authenticationProvider());
    }

    /**
     * Manages the configuration for specific http request.
     *
     * @param http HttpSecurity request
     * @throws Exception exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http.authorizeRequests()
                //configure security for pages
                .antMatchers("/static/**").permitAll()
                .antMatchers(new String[]{"/login", "/accessDenied"}).permitAll()
                .antMatchers("/**").access("hasAnyRole('admin', 'operatore', 'ufficio tecnico', 'processista')")
                .anyRequest().authenticated()
                //creates login form
                .and().formLogin().loginPage("/login").loginProcessingUrl("/login")
                .defaultSuccessUrl("/home").failureUrl("/accessDenied")
                .usernameParameter("id_utente").passwordParameter("password")
                //catches exceptions http 403 response
                .and().exceptionHandling().accessDeniedPage("/accessDenied");

        http.requestCache().disable();

        http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
    }

    /**
     * Manages the storage of user credentials inside database
     *
     * @return The authenticationProvider Object
     */
    @Bean
    public DaoAuthenticationProvider authenticationProvider()
    {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        return authenticationProvider;
    }

    @Bean
    public AuthenticationTrustResolver getAuthenticationTrustResolver()
    {
        return new AuthenticationTrustResolverImpl();
    }
}

关于 csrf 我在头部添加了jsp元标记 <sec:csrfMetaTags/> 它应该负责 csrf 保护或至少文件上说了这一点。
编辑2
通过如下更改ajax请求

<!-- change event of batch status script -->
function changeEventStatus(idEvento, statoEvento) {

    let csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
    let csrfToken = $("meta[name='_csrf']").attr("content");
    let csrfHeader = $("meta[name='_csrf_header']").attr("content");

    let data = {};
    let headers = {};

    data[csrfParameter] = csrfToken;
    data["id_evento"] = idEvento;
    data["stato"] = statoEvento;
    headers[csrfHeader] = csrfToken;

    $.ajax({
        url: 'http://localhost:8080/entsorgafin/events/api/cambiaStatoEvento',
        type: 'PUT',
        headers: headers,
        contentType: 'application/json',
        data: JSON.stringify(data)
    }).then(function (data) {
        console.log("process terminated.");
        console.log("data collected:");
        console.log(data);
    });
}

请求被正确执行,现在的问题是如何处理csrf令牌,因为spring试图反序列化并将其放入java对象( Evento 在这种情况下)和回馈

Failed to evaluate Jackson deserialization for type [[simple type, class com.entsorgafin.sr002EagleCloud.model.Evento]]
Could not resolve parameter [0] in public java.lang.String com.entsorgafin.sr002EagleCloud.controller.rest.EventsController_rest.changeEventStatus(com.entsorgafin.sr002EagleCloud.model.Evento): Content type 'application/json;charset=UTF-8' not supported
Completed 415 UNSUPPORTED_MEDIA_TYPE

请求的有效负载是:

{_csrf: "88c27418-7d48-4d76-a6ec-d76e7a45a61a", id_evento: 50, stato: "Attivo"}

如何指示spring boot不使用csrf令牌进行反序列化?

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题