删除操作返回错误:出现意外错误(类型=禁止,状态=403)。禁止的
Posted
技术标签:
【中文标题】删除操作返回错误:出现意外错误(类型=禁止,状态=403)。禁止的【英文标题】:DELETE operation returns ERROR: There was an unexpected error (type=Forbidden, status=403). Forbidden 【发布时间】:2019-11-27 07:53:37 【问题描述】:我正在开发一个 spring-boot 项目,其中包括 thymeleaf、spring-security。当我执行时它工作正常 - 显示产品列表、显示产品详细信息、添加新产品、更新现有产品。
但是当我执行 - 删除产品时,它会给出以下错误:
白标错误页面
此应用程序没有显式映射 /error,因此您将其视为后备。
2019 年 7 月 18 日星期四 16:59:16 BDT
出现意外错误(type=Forbidden,status=403)。
禁止
这是我的代码:
product_list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Product List</title>
<link rel="stylesheet" th:href="@/css/bootstrap.css">
</head>
<body>
<div class="container">
<h1>Product List</h1>
<hr>
<a class="btn btn-success" th:href="@/products/add">Create New Product</a>
<hr>
<table class="table">
<thead>
<tr>
<th>Product ID</th>
<th>Name</th>
<th>Brand</th>
<th>Made In</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr th:each="theProduct:$theProducts">
<td th:text="$theProduct.id">Product ID</td>
<td th:text="$theProduct.name">Name</td>
<td th:text="$theProduct.brand">Brand</td>
<td th:text="$theProduct.madein">Made In</td>
<td th:text="$theProduct.price">Price</td>
<td>
<a class="btn btn-info" th:href="@'/products/show/' + $theProduct.id">View</a>
<a class="btn btn-warning" th:href="@'/products/edit/' + $theProduct.id">Edit</a>
<a class="btn btn-danger" th:data-the-product-id="$theProduct.id" data-toggle="modal" data-target="#deleteConfirmationModal">Delete</a>
<div class="modal fade" id="deleteConfirmationModal" tabindex="-1" role="dialog" aria-labelledby="deleteConfirmationModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Delete Confirmation</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Are you sure you want to DELETE the Product.
<br>
<form id="deleteForm" action="#" th:method="DELETE">
<button type="submit" class="btn btn-danger">Delete Employee</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<script th:src="@/js/jquery-3.3.1.js"></script>
<script th:src="@/js/popper.js"></script>
<script th:src="@/js/bootstrap.js"></script>
<script>
$('#deleteConfirmationModal').on('show.bs.modal', function (event)
var anchorLink = $(event.relatedTarget)
var theProductId = anchorLink.data('theProductId')
var modal = $(this)
$("#deleteForm").attr("action", "/products/delete/" + theProductId)
)
</script>
</body>
</html>
ProductController.java
package com.example.demo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.demo.dao.ProductRepository;
import com.example.demo.entity.Product;
@Controller
@RequestMapping("/products")
public class ProductController
@Autowired
private ProductRepository productRepository;
@GetMapping("/index")
public String index(Model theModel)
List<Product> theProducts = productRepository.findAll();
theModel.addAttribute("theProducts", theProducts);
return "product/product_list";
@GetMapping("/add")
public String add(Model theModel)
Product theProduct = new Product();
theModel.addAttribute("theProduct", theProduct);
return "product/product_add_form";
@GetMapping("/show/productId")
public String show(@PathVariable int productId, Model theModel)
Product theProduct = productRepository.findById(productId).get();
if(theProduct == null)
return null;
theModel.addAttribute("theProduct", theProduct);
return "product/product_detail";
@PostMapping("/create")
public String create(@ModelAttribute("theProduct") Product theProduct)
theProduct.setId(0);
productRepository.save(theProduct);
return "redirect:/products/index";
@GetMapping("/edit/productId")
public String edit(@PathVariable(name="productId") int productId, Model theModel)
Product theProduct = productRepository.findById(productId).get();
theModel.addAttribute("theProduct", theProduct);
return "product/product_edit_form";
@PutMapping("/update")
public String update(@ModelAttribute("theProduct") Product theProduct)
productRepository.save(theProduct);
return "redirect:/products/index";
@DeleteMapping("/delete/productId")
public String delete(@PathVariable int productId)
Product tempProduct = productRepository.findById(productId).get();
if(tempProduct == null)
return null;
productRepository.deleteById(productId);
return "redirect:/products/index";
LoginController.java
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController
@RequestMapping("/login")
public String login()
return "login";
@GetMapping("/")
public String home(Model theModel)
return "redirect:/products/index";
SecurityConfig.java
package com.example.demo.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.User.UserBuilder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
UserBuilder users = User.withDefaultPasswordEncoder();
auth.inMemoryAuthentication().withUser(users.username("admin").password("Admin.123").roles("EMPLOYEE", "ADMIN"));
@Override
protected void configure(HttpSecurity http) throws Exception
http.authorizeRequests()
.antMatchers("/css/**")
.permitAll()
.antMatchers("/js/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/authenticateTheUser")
.permitAll()
.and()
.logout()
.permitAll();
【问题讨论】:
【参考方案1】:尝试在您的配置中禁用 csrf
令牌:
@Override
protected void configure(HttpSecurity http) throws Exception
http.authorizeRequests()
.antMatchers("/css/**")
.permitAll()
.antMatchers("/js/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/authenticateTheUser")
.permitAll()
.and()
.logout()
.permitAll()
.and().csrf().disable();
【讨论】:
你是对的......我测试了他的代码......但是出于安全原因,csrf非常重要......即使是为了测试目的【参考方案2】:我想问题是你错过了删除按钮的 th:href。
【讨论】:
【参考方案3】:幸运的是,您在每个循环中都添加了“模态”,因此请根据我的代码编辑您的 html ....
<form id="deleteForm" th:action="$'/products/delete/' + theProductId" th:method="DELETE">
<button type="submit" class="btn btn-danger">Delete Employee</button>
</form>
这是经过测试的代码......工作正常......你只是错过了“th:action”,因为它不能作为百里香形式工作。所以百里香不提供隐藏的“_csrf”字段;
【讨论】:
感谢它的工作。实际上我在开头添加了th:action="$'/products/delete/' + theProductId"
。但是我在 javascript 中做错了什么,然后删除了th:action
。然后解决了JavaScript问题,但忘记添加th:action
:p以上是关于删除操作返回错误:出现意外错误(类型=禁止,状态=403)。禁止的的主要内容,如果未能解决你的问题,请参考以下文章
Whitelabel 错误页面出现意外错误(类型=内部服务器错误,状态=500)。空标识符
TortoiseSVN 中继结帐“服务器发送了意外的返回值(403 禁止)以响应 OPTIONS”错误