如果未经授权如何定位错误消息
How to localize the error message if unauthorized
这是一个 asp.net 核心 webapi 项目,我只是简单地放置了 [Authorize] 属性来保护那些 api。如果用户未被授权,api 将 return “401 未授权”。
我的问题是,如果未经授权,如何本地化“401 未经授权”消息。
对于其他数据注释,我可以设置DataAnnotaion属性的ErrorMessage 属性,比如[Required(ErrorMessage = "xxx")]。但是,AuthorizeAttribute 没有这样的 属性。
感谢@Athanasios,我想出了我的解决方案,希望它可以帮助别人。 (ErrorMessages 只是共享 class)。
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(),
};
}
}
}
}
}
}
以上代码将return一个问题详情给客户端。
您需要像这样创建一个自定义属性:
https://docs.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;
}
}
那么您可以使用您自己的而不是授权属性。
更具体的例子
如果您检查 documentation here,您会发现除了创建自定义属性之外别无他法。
这是一个 asp.net 核心 webapi 项目,我只是简单地放置了 [Authorize] 属性来保护那些 api。如果用户未被授权,api 将 return “401 未授权”。
我的问题是,如果未经授权,如何本地化“401 未经授权”消息。
对于其他数据注释,我可以设置DataAnnotaion属性的ErrorMessage 属性,比如[Required(ErrorMessage = "xxx")]。但是,AuthorizeAttribute 没有这样的 属性。
感谢@Athanasios,我想出了我的解决方案,希望它可以帮助别人。 (ErrorMessages 只是共享 class)。
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(),
};
}
}
}
}
}
}
以上代码将return一个问题详情给客户端。
您需要像这样创建一个自定义属性: https://docs.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;
}
}
那么您可以使用您自己的而不是授权属性。
更具体的例子
如果您检查 documentation here,您会发现除了创建自定义属性之外别无他法。