簡體   English   中英

如何將數據從 AuthorizationHandler 傳遞到 Asp.net 核心中的控制器

[英]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 顯示您的消息

你需要ITempDataDictionaryFactoryIHttpContextAccessor或者你可以從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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM