【问题标题】:How can pass data from AuthorizationHandler to Controller in Asp.net core如何将数据从 AuthorizationHandler 传递到 Asp.net 核心中的控制器
【发布时间】:2018-01-18 03:49:16
【问题描述】:

我为用户登录使用了特定的授权策略,因此创建了自定义授权处理程序。如果他们未能通过策略,我想显示使用特定的警报消息。我阅读了documentation,发现我可以通过强制转换 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

【问题讨论】:

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


    【解决方案1】:

    使用 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"; 将只能用于当前请求,当您在控制器或其方法中使用 Authorization 时,它将向您插入消息到当前请求并重定向到您的 AccessDeniedPath 或 LoginPath 和将为此请求创建新的HttpContext,而无需您的消息。要在请求之间共享一些信息,您可以使用 TempData 或其他方法。

    更新尝试从访问器获取httpContext 此处完整代码

    添加到启动services.AddSingleton&lt;IHttpContextAccessor, HttpContextAccessor&gt;();

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

    更新 当 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;
        }
    }
    

    【讨论】:

    • 谢谢,我应该使用哪个 TempDataProvider 来生成 TempDataDictionaryFactory?
    • 你不需要创建它,你应该使用DI来获取它。你能分享你的授权处理程序吗?
    • @itkhomi 刚刚做了,我想添加这样的构造函数会解决这个问题。
    • @ringord,当然,现在尝试让它工作。只需将 TempDataDictionaryFactory 更改为您注入的 _tempDictionaryFactory
    • 好吧,我刚试了一下,当我在控制器(帐户/登录)中访问时,TempData 没有元素。
    【解决方案2】:

    在 API 控制器的 asp.net 核心中,请注意我使用的是 _httpContext.Items,例如:

    _httpContext.Items["Token"] = token 在那里你可以存储你想要的任何对象。

    在控制器中只需这样做:

    return HttpContext.Items["Token"] 作为自定义令牌;

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

    【讨论】:

    • 我的回答与 asp.net core 有关
    猜你喜欢
    • 2019-07-06
    • 1970-01-01
    • 2021-03-19
    • 2020-06-17
    • 1970-01-01
    • 2018-09-20
    • 1970-01-01
    • 2021-09-27
    相关资源
    最近更新 更多