[英]How can pass data from AuthorizationHandler to Controller in Asp.net core
我对用户登录使用了特定的授权策略,因此创建了自定义授权处理程序。 如果他们未能通过政策,我想显示使用特定的警报消息。 我阅读了文档,发现我可以通过转换 AuthorizationHandlerContext 来访问 AuthorizationFilterContext。 我试图将消息添加到 HttpContext.Items 属性并在我的控制器中访问它,但是当我使用 TryGetValue 方法检查它时它返回 false。
if (context.HasFailed && context.Resource is AuthorizationFilterContext mvcContext)
{
mvcContext.HttpContext.Items["message"] = "alert message";
}
这是我在控制器操作中使用的代码,将在授权失败时执行,
public IActionResult Login()
{
bool t = HttpContext.Items.TryGetValue("message", out Object e);
//t is false
TempData["message"] = e as string;
return View();
}
这是我注册所有身份验证服务的启动类。
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.AccessDeniedPath = "/Account/Login";
options.LoginPath = "/Account/Login";
});
services.AddAuthorization(options =>
{
options.AddPolicy("CustomRequirement", policy => policy.Requirements.Add(new CustomRequirement()));
});
有什么办法可以解决吗?
添加了完整的处理程序。
public class CustomRequirementHandler : AuthorizationHandler<CustomRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement)
{
Dictionary<string, string> claims = context.User.Claims.ToDictionary(p => p.Type, p => p.Value);
if (claims.TryGetValue("SessionId", out string sessionId) && claims.TryGetValue("UserId", out string userName) )
{
bool qq = ;//we check session id and user id that is stored in our database, true if valid.
if (qq)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
else
{
context.Fail();
}
if (context.HasFailed && context.Resource is AuthorizationFilterContext mvcContext)
{
var tempData = _tempDictionaryFactory.GetTempData(mvcContext.HttpContext);
tempData["message"] = "alert message";
}
return Task.CompletedTask;
}
}
我想添加这会使依赖注入?
private ITempDataDictionaryFactory _tempDictionaryFactory;
public SingleConcurrentSessionHandler(ITempDataDictionaryFactory tempDataDictionaryFactory)
{
_tempDictionaryFactory = tempDataDictionaryFactory;
}
更新- 这是带有自定义 AuthorizationHandler 的新空项目的记录器日志。
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:50236/
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed for user: (null).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes ().
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[12]
AuthenticationScheme: Cookies was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action WebApplication1.HomeController.Index (WebApplication1) in 6217.0905ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 6389.8033ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:50236/Account/Login?ReturnUrl=%2F
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method WebApplication1.Controllers.AccountController.Login (WebApplication1) with arguments ((null)) - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.Formatters.Json.Internal.JsonResultExecutor[1]
Executing JsonResult, writing value .
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action WebApplication1.Controllers.AccountController.Login (WebApplication1) in 3723.1458ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 3741.0345ms 200 application/json; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:50236/favicon.ico
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 4.1151ms 404 text/plain
使用 TempData 显示您的消息
你需要ITempDataDictionaryFactory
和IHttpContextAccessor
或者你可以从mvcContext.HttpContext
获取mvcContext.HttpContext
if (context.HasFailed && context.Resource is AuthorizationFilterContext mvcContext)
{
var tempData = _tempDataDictionaryFactory.GetTempData(mvcContext.HttpContext);
tempData["message"] = "alert message";
}
然后您可以通过 TempData 在 Login 方法中获取它
public IActionResult Login()
{
string message = null;
var item = TempData.FirstOrDefault(x =>x.Key == key);
if (item.Value != null)
{
message = (string)item.Value;
}
return View();
}
为什么你的代码不起作用:
每个请求创建HttpContext
这意味着您插入mvcContext.HttpContext.Items["message"] = "alert message";
将只能用于当前请求,当您在控制器或他的方法中使用授权时,它会将您的消息插入到当前请求并重定向到您的 AccessDeniedPath 或 LoginPath,并且将为此请求创建新的HttpContext
而不包含您的消息。 要在请求之间共享一些信息,您可以使用 TempData 或其他方法。
更新尝试从访问器获取 httpContext 完整代码
添加到启动services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
public class CustomRequirementHandler : AuthorizationHandler<CustomRequirement>
{
private readonly IHttpContextAccessor _httpContext;
private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory;
public CustomRequirementHandler(IHttpContextAccessor httpContext, ITempDataDictionaryFactory tempDataDictionary)
{
_httpContext = httpContext;
_tempDataDictionaryFactory = tempDataDictionary;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement)
{
///////
//Your logic
///////
if (context.HasFailed)
{
var tempData = _tempDataDictionaryFactory.GetTempData(_httpContext.HttpContext);
tempData["message"] = "alert message";
}
return Task.CompletedTask;
}
}
UPDATE当 context.Fail(); 执行的 tempData 不通过 tempdata 提供程序注入,但您可以调用 tempdata 提供程序来执行手动保存
这里的例子:
public class CustomRequirementHandler : AuthorizationHandler<CustomRequirement>
{
private readonly ITempDataProvider _tempDataProvider;
public CustomRequirementHandler(ITempDataProvider tempDataProvider)
{
_tempDataProvider = tempDataProvider;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement)
{
///////
//Your logic
///////
context.Fail();
if (context.HasFailed && context.Resource is AuthorizationFilterContext mvcContext)
{
_tempDataProvider.SaveTempData(mvcContext.HttpContext, new Dictionary<string, object>() { { "message","alertmessage "+DateTime.Now } });
}
return Task.CompletedTask;
}
}
在 API 控制器的 asp.net 核心中,请注意我使用的是_httpContext.Items
,例如:
_httpContext.Items["Token"] = token
,您可以在其中存储您想要的任何对象。
在控制器中只需执行以下操作:
return HttpContext.Items["Token"]
作为 CustomToken;
public class HasConstituentIdHandler : AuthorizationHandler<HasConstituentIdRequirement>
{
private readonly OpenIddictTokenManager<CustomToken> _tokenManager;
private readonly HttpContext _httpContext;
public HasConstituentIdHandler(OpenIddictTokenManager<CustomToken> tokenManager, IHttpContextAccessor httpContextAccessor)
{
_tokenManager = tokenManager;
_httpContext = httpContextAccessor.HttpContext;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, HasConstituentIdRequirement requirement)
{
var tokenId = context.User.GetTokenId();
if (tokenId != null)
{
var token = await _tokenManager.FindByIdAsync(tokenId);
token.Context = new EventContext {ConstituentId = "junk"};//todo: s.f for now
if (!string.IsNullOrWhiteSpace(token?.Context?.ConstituentId))
{
if (_httpContext != null) _httpContext.Items["Token"] = token;
context.Succeed(requirement);
}
}
if (_httpContext != null)
{
var response = _httpContext.Response;
var bytes = Encoding.UTF8.GetBytes("Missing constituent information! Please log in again.");
response.StatusCode = (int) HttpStatusCode.Unauthorized;
response.ContentType = "application/json";
await response.Body.WriteAsync(bytes, 0, bytes.Length);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.