【问题标题】:How to enable custom authorization messages如何启用自定义授权消息
【发布时间】:2020-09-23 17:23:17
【问题描述】:

免责声明:该主题的结果通常很旧,不一定指使用 Identity Core 的 Asp.Net Core 3.1。我正在尝试寻找一个现代的推荐解决方案。

我使用 Identity 和 JWT 创建了一个概念验证 Web API 应用程序。这个想法是导航到该网站,并能够登录并查看您的声明、更改您的密码以及 Identity 附带的其他功能。

另一个组件是仅将 Web API 与 JWT 一起使用。

我已经实施了声明/政策,并且授权运作良好。总的来说,我对这个概念验证感到满意。

特别是还有很多不足之处:当用户未通过身份验证,或在使用 JWT 使用 API 时经过身份验证但未授权时的消息。目前它所做的只是返回没有相关消息的 403(已验证但未授权)或 401(未验证)响应代码。

举个例子。我有一个声明,ClaimType: Api, ClaimValue: Delete 映射到一个策略(字符串常量以避免魔术字符串):CanDeletePolicy

options.AddPolicy(Policies.CanDeletePolicy, policy => {
    policy.RequireClaim("Api", "Delete");
});

请记住,一切都按预期工作。我只是想为 API 的使用者提供有意义的消息。

控制器:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[Route("[controller]")]
[Produces("application/json")]

public class PeopleController : ControllerBase {
    private readonly ILogger<PeopleController> _logger;
    private readonly IPeopleService _peopleService;

    public PeopleController(ILogger<PeopleController> logger, IPeopleService peopleService) {
        _logger = logger;
        _peopleService = peopleService;
    }

    ...

PeopleController 中的操作:

[HttpDelete("[action]/{id:int}")]
[Authorize(Policy = Policies.CanDeletePolicy)]
public IActionResult Delete(int id) {
    var result = _peopleService.Delete(id);

    var username = User.FindFirstValue(ClaimTypes.Name);

    if (result < 1) {
        var message = $"User '{username}' was unable to delete a person with Id {id}";
        _logger.LogError(message);

        return BadRequest(new {
            Message = message
        });
    }

    var successMessage = $"User '{username}' successfully deleted the person with Id {id}";
    _logger.LogDebug(successMessage);

    return Ok(new {
        Message = "Person deleted"
    });
}

如果用户尝试使用此操作:

  • 但未通过身份验证,它们会收到空的 401 响应
  • 已通过身份验证,但未授权,它们收到空的 403 响应

我想提供不同程度的信息:

  • 401 响应正文“您未通过身份验证”

  • 403 响应正文“您未获得授权”或“您未获得授权:Api,需要更新”

我有哪些选择?创建自定义授权属性?我宁愿不要为了添加一个简单的信息而重新发明轮子。我也希望以 JSON 格式做出授权响应,但我认为这对于提议的解决方案并不重要。

【问题讨论】:

    标签: c# asp.net-core jwt asp.net-core-identity


    【解决方案1】:
       public class ResponseFormatterMiddleware
    {
        private readonly RequestDelegate _next;
    
        public ResponseFormatterMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {
            await _next.Invoke(context);
    
            if (context.Response.StatusCode == StatusCodes.Status401Unauthorized)
            {
                await context.Response.WriteAsync(
                    JsonConvert.SerializeObject(new ResponseModel("some-message")));
            }
        }
    }
    
    public class ResponseModel
    {
        public ResponseModel(string message)
         {
            this.Message = message;
         }
    
         public string Message { get; set; }
    }
    

    在启动时:

          public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // put middleware before authentication
            app.UseMiddleware<ResponseFormatterMiddleware>();
            app.UseAuthentication();
        }
    

    【讨论】:

    • 什么是RequestLogger,为什么没有被使用? ResponseModel 是自定义类还是 RequestLogger 附带的?这些都是DevExpress 的一部分吗?
    • 对不起。我复制粘贴代码并忘记删除 RequestLogger 。 ResponseModel 是一个简单的类,只有用于响应的消息属性。不,它们不是 DevExpress 的一部分
    • 非常有趣。这有很大帮助。我可以看到context 内部我可以访问User 属性并检索他们的声明,但我认为我无法访问请求的要求。看起来我充其量只能说“访问被拒绝,这是您的声明”,而不是“访问被拒绝,所需声明是:”仍然非常感谢。这符合我的最低要求。
    猜你喜欢
    • 2023-03-27
    • 2019-10-21
    • 1970-01-01
    • 1970-01-01
    • 2017-07-19
    • 2015-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多