c# - 如果未经授权如何本地化错误消息

标签 c# asp.net-core-webapi asp.net-core-localization

这是一个asp.net core webapi项目,我只是简单地添加了[Authorize]属性来保护这些api。如果用户未授权,API 将返回“401 未经授权”。

我的问题是,如果未经授权,如何本地化“401 未经授权”消息。

对于其他数据注释,我可以设置 DataAnnotation Attribute 的 ErrorMessage 属性,例如 [Required(ErrorMessage = "xxx")]。但是,AuthorizeAttribute 没有这样的属性。

感谢@Athanasios,我想出了我的解决方案,希望它可以帮助别人。 (ErrorMessages 只是一个共享类)。

using System;
using System.Threading.Tasks;

using YourNamespace.Messages;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;

namespace YourNamespace.Attributes
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class LocalizedAuthorizeAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
    {
        public string UnauthorizedErrorMessage { get; set; }
        public string ForbiddenErrorMessage { get; set; }

        public LocalizedAuthorizeAttribute()
        {
        }

        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var user = context.HttpContext.User;
            var localizer = context.HttpContext.RequestServices.GetService<IStringLocalizer<ErrorMessages>>();
            var logger = context.HttpContext.RequestServices.GetService<ILogger<LocalizedAuthorizeAttribute>>();

            string url = $"{context.HttpContext.Request.Scheme}://{context.HttpContext.Request.Host}{context.HttpContext.Request.Path}{context.HttpContext.Request.QueryString}";
            if (!user.Identity.IsAuthenticated)
            {
                logger.LogInformation($"Unauthroized access to '{url}' from {context.HttpContext.Connection.RemoteIpAddress.ToString()}");

                UnauthorizedErrorMessage = UnauthorizedErrorMessage ?? "Unauthorized";
                ProblemDetails problemDetails = new ProblemDetails()
                {
                    Title = localizer[UnauthorizedErrorMessage],
                    Detail = localizer[UnauthorizedErrorMessage + "_Detail"],
                    Status = StatusCodes.Status401Unauthorized
                };
                context.Result = new ObjectResult(problemDetails)
                {
                    StatusCode = StatusCodes.Status401Unauthorized,
                    DeclaredType = problemDetails.GetType(),
                };
            }
            else
            {
                ForbiddenErrorMessage = ForbiddenErrorMessage ?? "Forbidden";
                var authorizeService = context.HttpContext.RequestServices.GetService<IAuthorizationService>();

                if (!String.IsNullOrWhiteSpace(Policy))
                {
                    AuthorizationResult result = await authorizeService.AuthorizeAsync(user, Policy);

                    if (!result.Succeeded)
                    {
                        logger.LogWarning($"Forbidden access to '{url}' from {context.HttpContext.Connection.RemoteIpAddress.ToString()}");

                        ProblemDetails problemDetails = new ProblemDetails()
                        {
                            Title = localizer[ForbiddenErrorMessage],
                            Detail = localizer[ForbiddenErrorMessage + "_Detail"],
                            Status = StatusCodes.Status403Forbidden
                        };
                        context.Result = new ObjectResult(problemDetails)
                        {
                            StatusCode = StatusCodes.Status403Forbidden,
                            DeclaredType = problemDetails.GetType(),
                        };
                    }
                }
            }
        }
    }
}

以上代码将向客户端返回问题详细信息。

最佳答案

您需要创建一个如下所示的自定义属性: https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/authentication-filters

public class AuthenticationFailureResult : IHttpActionResult
{
    public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
    {
        ReasonPhrase = reasonPhrase;
        Request = request;
    }

    public string ReasonPhrase { get; private set; }

    public HttpRequestMessage Request { get; private set; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(Execute());
    }

    private HttpResponseMessage Execute()
   {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        response.RequestMessage = Request;
        response.ReasonPhrase = ReasonPhrase;
        return response;
   }
}

然后您可以使用您自己的属性来代替 Authorize 属性。

更具体的示例 check this SO answer here

如果您检查 documentation here ,您会发现除了创建自定义属性之外没有其他方法可以做到这一点。

关于c# - 如果未经授权如何本地化错误消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59262573/

相关文章:

c# - 控制流从模型返回而不进入 Controller 操作

authentication - Azure 应用服务身份验证的 HttpContext 用户为空

asp.net-core - ASP.NET Core 2.1 中 [ApiController] 中的 POST 操作

c# - 维护插入顺序并允许通过其索引访问元素的集合

javascript - 突出显示 jQuery 日期选择器中的特定日期

C# 与 Access 数据库出现插入语法错误

json - 如何覆盖 Json.Net 模型绑定(bind)异常消息以实现本地化?

asp.net-core - ASP.NET Core IViewLocalizer 不提取我的字典查找值

c# - 以英语以外的特定语言获取 ASP.NET Core 模型错误

c# - 使用 linq 查询 xmlnode