ASP.NET Core控制器如何获取Antiforgery Token并嵌入Kendo Grid表单
解决方案
方法1:在控制器Action中获取防伪令牌
你可以通过ASP.NET Core内置的IAntiforgery服务直接在控制器中获取__RequestVerificationToken,步骤如下:
- 在控制器构造函数中注入
IAntiforgery服务 - 在
Search方法中调用GetAndStoreTokens方法获取当前请求对应的防伪令牌 - 修改Grid的ClientTemplate,在动态生成的表单中添加令牌隐藏域
控制器代码修改示例
public class ItemsController : Controller { private readonly IAntiforgery _antiforgery; private readonly IItemService _Service; public ItemsController(IAntiforgery antiforgery, IItemService service) { _antiforgery = antiforgery; _Service = service; } [HttpPost] [Route("items/search")] public async Task<ActionResult> Search([DataSourceRequest] DataSourceRequest request) { // 获取当前会话的防伪令牌,同一会话下所有请求的令牌通用 var requestToken = _antiforgery.GetAndStoreTokens(HttpContext).RequestToken; var workItems = await _Service.GetItems(); var result = workItems.Select(x => new ItemModel() { ID = x.ID, Name = x.Name, Token = requestToken }).ToList().ToDataSourceResult(request); return Json(result); } [HttpPost] [Route("items/{id}/copy")] public async Task<ActionResult> Copy([FromRoute]int id) { // 此处执行业务逻辑 } }
Grid代码修改示例
@(Html.Kendo().Grid<ItemModel>() .Name("SearchItems") .Columns(col => { col.Bound(p => p.ID).Title("ID").Width(75); col.Bound(p => p.Name); col.Bound(p => p.ID).ClientTemplate("<form method='post' action='/items/#: ID #/copy'><input type='hidden' name='__RequestVerificationToken' value='#: Token #' /><button type='submit' class='btn btn-link'>copy</button></form>"); }) .AutoBind(true) .DataSource(dataSource => dataSource .Ajax() .Model(m=>m.Id(p=>p.WorkItemID)) .PageSize(50) .ServerOperation(true) .Read(read => read.Action("Search", "Items")) ) )
方法2:更优实现(无需修改控制器代码)
因为同一会话下防伪令牌是通用的,不需要给每个列表项单独赋值,你可以直接在Razor视图中提前获取令牌,直接注入到ClientTemplate中即可:
- 在Razor视图顶部注入
IAntiforgery服务,把令牌存为全局JS变量 - 直接在ClientTemplate中引用全局令牌变量
Razor视图代码示例
@inject IAntiforgery Antiforgery @* 其他页面代码 *@ <script> // 页面加载时直接获取当前会话的防伪令牌 const globalAntiForgeryToken = '@Antiforgery.GetAndStoreTokens(HttpContext).RequestToken'; </script> @(Html.Kendo().Grid<ItemModel>() .Name("SearchItems") .Columns(col => { col.Bound(p => p.ID).Title("ID").Width(75); col.Bound(p => p.Name); col.Bound(p => p.ID).ClientTemplate("<form method='post' action='/items/#: ID #/copy'><input type='hidden' name='__RequestVerificationToken' value='" + globalAntiForgeryToken + "' /><button type='submit' class='btn btn-link'>copy</button></form>"); }) .AutoBind(true) .DataSource(dataSource => dataSource .Ajax() .Model(m=>m.Id(p=>p.WorkItemID)) .PageSize(50) .ServerOperation(true) .Read(read => read.Action("Search", "Items")) ) )
这个方法不需要修改控制器代码,也避免了给每个列表项重复赋值相同令牌的冗余操作。
内容的提问来源于stack exchange,提问作者LP13
相关产品推荐
相关产品推荐

