c# - 如何将数据从 AuthorizationHandler 传递到 Asp.net Core 中的 Controller

标签 c# asp.net-core asp.net-core-mvc asp.net-core-2.0

我为用户登录使用了特定的授权策略,因此创建了自定义授权处理程序。如果政策失败,我想显示使用特定的警报消息。我读了documentation并发现我可以通过转换 AuthorizationHandlerContext 来访问 AuthorizationFilterContext。我尝试将消息添加到 HttpContext.Items 属性并在我的 Controller 中访问它,但是当我使用 TryGetValue 方法检查它时它返回 false。

if (context.HasFailed && context.Resource is AuthorizationFilterContext mvcContext)
{
 mvcContext.HttpContext.Items["message"] = "alert message";
}

这是我在 Controller 操作中使用的代码,将在授权失败时执行,

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;
    }
}

我想添加这个会使依赖注入(inject)?

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 显示您的消息

有你需要的ITempDataDictionaryFactoryIHttpContextAccessor或者对于上下文,您可以从 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";将只能针对当前请求,当您在 Controller 或其方法中使用授权时,它将向您插入消息到当前请求并重定向到您的 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 提供程序注入(inject),但您可以调用 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;
    }
}

关于c# - 如何将数据从 AuthorizationHandler 传递到 Asp.net Core 中的 Controller,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48313547/

相关文章:

oauth-2.0 - 如何在 ASP.NET Core MVC OAuth 2.0 中获取访问 token 的值

c# - 如何使用 Travis CI 构建混合 (C++ + C#) 解决方案?

c# - ASP.NET Web API 自定义发布操作不起作用

asp.net-core - ASP.NET Core - 在运行时更改 JWT SecurityKey

c# - asp.net core 5.0 模拟框架

c# - Dotnet 核心 MVC xml 参数绑定(bind)总是给 null

asp.net-core - 使用Moq进行ASP.NET核心集成测试和模拟

C#串口检查设备是否连接

c# - 用另一个元素包装一个 HTML 元素?

c# - ASP.NET : relative paths not working when deployed IIS