简体   繁体   English

如何将数据从 AuthorizationHandler 传递到 Asp.net 核心中的控制器

[英]How can pass data from AuthorizationHandler to Controller in Asp.net core

I used a specific authorization policy for user log in, so created custom Authorization Handler.我对用户登录使用了特定的授权策略,因此创建了自定义授权处理程序。 And I would like to display use a specific alert message if they failed the policy.如果他们未能通过政策,我想显示使用特定的警报消息。 I read the documentation and found that I could access AuthorizationFilterContext via casting AuthorizationHandlerContext.我阅读了文档,发现我可以通过转换 AuthorizationHandlerContext 来访问 AuthorizationFilterContext。 I tried to add message to HttpContext.Items property and access it in my controller, but it returns false when i check it with TryGetValue method.我试图将消息添加到 HttpContext.Items 属性并在我的控制器中访问它,但是当我使用 TryGetValue 方法检查它时它返回 false。

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

and this is the code i used in controller action that will be executed when authorization has failed,这是我在控制器操作中使用的代码,将在授权失败时执行,

public IActionResult Login()
        {
            bool t = HttpContext.Items.TryGetValue("message", out Object e);
            //t is false
            TempData["message"] = e as string;
            return View();
        }

and this is startup class where i registered all authentication services.这是我注册所有身份验证服务的启动类。

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

Is there any way i could work it out?有什么办法可以解决吗?


added full handler.添加了完整的处理程序。

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

I guess add this will make dependency injected?我想添加这会使依赖注入?

private ITempDataDictionaryFactory _tempDictionaryFactory;

        public SingleConcurrentSessionHandler(ITempDataDictionaryFactory tempDataDictionaryFactory)
        {
            _tempDictionaryFactory = tempDataDictionaryFactory;
        }

Update - here is the logger log for new empty project with custom AuthorizationHandler.更新- 这是带有自定义 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

Use TempData to show your message使用 TempData 显示您的消息

There are you need ITempDataDictionaryFactory and IHttpContextAccessor or for context you can get from mvcContext.HttpContext你需要ITempDataDictionaryFactoryIHttpContextAccessor或者你可以从mvcContext.HttpContext获取mvcContext.HttpContext

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

then you can get it in Login method via TempData然后您可以通过 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();
}

Why your code not working:为什么你的代码不起作用:

HttpContext creating per request it means that you inserting mvcContext.HttpContext.Items["message"] = "alert message";每个请求创建HttpContext这意味着您插入mvcContext.HttpContext.Items["message"] = "alert message"; will be able only for current request, when you use Authorization in controller or his method it will insert you message to current request and redirect to your AccessDeniedPath or LoginPath and new HttpContext will be created for this request without your message.将只能用于当前请求,当您在控制器或他的方法中使用授权时,它会将您的消息插入到当前请求并重定向到您的 AccessDeniedPath 或 LoginPath,并且将为此请求创建新的HttpContext而不包含您的消息。 To share some info between requests you can use TempData or other methods.要在请求之间共享一些信息,您可以使用 TempData 或其他方法。

Update Try to get httpContext from accessor Here full code更新尝试从访问器获取 httpContext 完整代码

add to startup services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();添加到启动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 When context.Fail(); UPDATE当 context.Fail(); performed tempData dont injecting via tempdata provider but you can call tempdata provider for executing manual save执行的 tempData 不通过 tempdata 提供程序注入,但您可以调用 tempdata 提供程序来执行手动保存

Here example:这里的例子:

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

In asp.net core for an API controller, note that I'm using _httpContext.Items , eg:在 API 控制器的 asp.net 核心中,请注意我使用的是_httpContext.Items ,例如:

_httpContext.Items["Token"] = token and in there you can store whatever object you want. _httpContext.Items["Token"] = token ,您可以在其中存储您想要的任何对象。

In the controller simply do this:在控制器中只需执行以下操作:

return HttpContext.Items["Token"] as CustomToken; 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.

相关问题 ASP.NET 核心 AuthorizationHandler 未被调用 - ASP.NET Core AuthorizationHandler not being called asp.net核心-如何将变量从控制器传递到过滤器 - asp.net core - How to pass variable from controller to filter 如何将数据从数据库从一个控制器传递到在ASP.NET Core中拥有自己的数据库的另一个控制器? - How do I pass data from a database from one controller to another controller that has its own database in ASP.NET Core? 如何从 AuthorizationHandler .NET Core 获取参数 - How to get params from AuthorizationHandler .NET Core 如何将数据从 Controller 传递到 ASP.NET MVC 中的 WebForm? - How to pass data from Controller to WebForm in ASP.NET MVC? 如何将数据从控制器传递到 ASP.NET MVC 中查看 - How to to pass data from controller to view in ASP.NET MVC 在 C# ASP.NET Core MVC 中使用 AJAX 将数据从视图传递到控制器 - Pass data from view to controller using AJAX in C# ASP.NET Core MVC 如何将两个参数传递给 ASP.NET Core MVC 中的 controller? - How to pass two parameters to a controller in ASP.NET Core MVC? 如何使用asp.net核心中的Fetch api将数据传递给控制器 - How to pass data to controller using Fetch api in asp.net core 如何将自定义对象从异步操作过滤器传递到 ASP.net 核心中的控制器? - How do I pass an custom object from an async action filter to a controller in ASP.net core?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM