我有一个使用 ASP.NET WEB API 2 开发的现有 REST API,其中通过将所有控制器名称和操作方法详细信息存储在 xml 文件中来处理授权。
WebAPIAuthorization.xml:
<?xml version="1.0" encoding="utf-8" ?>
<WebApiAuthorizationSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<WebApiControllerAuthorizationSettings>
<WebApiControllerAuthorizationSetting>
<ControlerName>Profile</ControlerName>
<IsAuthorizationRequired>true</IsAuthorizationRequired>
<WebApiActionAuthorizationSettings>
<WebApiActionAuthorizationSetting>
<ActionName>GetProfile</ActionName>
<IsAuthorizationRequired>true</IsAuthorizationRequired>
</WebApiActionAuthorizationSetting>
</WebApiActionAuthorizationSettings>
</WebApiControllerAuthorizationSetting>
</WebApiControllerAuthorizationSettings>
</WebApiAuthorizationSettings>
代码:
public class CommonResponserHandler : DelegatingHandler
{
ICommonService _commonService = new CommonService();
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string locale = string.Empty;
if (request.Headers.Contains(Constants.REQUEST_HEADER_ACEPT_LANGUAGE))
{
locale = request.Headers.GetValues(Constants.REQUEST_HEADER_ACEPT_LANGUAGE).First();
}
bool initialAuthorizationStatus = GetInitialAuthorization(request);
var response = await base.SendAsync(request, cancellationToken);
APIResult commonResponse;
if (response.TryGetContentValue<APIResult>(out commonResponse))
{
//populate common response here;
UpdateCommonResponse(request, response, commonResponse);
HttpResponseMessage newResponse;
bool authorizatinCheckResult = AssertAuthorization(initialAuthorizationStatus, request);
if (authorizatinCheckResult)
{
newResponse = request.CreateResponse(response.StatusCode, commonResponse);
}
else
{
var unAuthorisedResult = new APIResult{Authorized = false, UserMessage = Constants.Unauthorized, Locale = new Locale(_commonService.GetLanguageFromLocale(locale))};
newResponse = request.CreateResponse(HttpStatusCode.Unauthorized, unAuthorisedResult);
var jsonSerializerSettings = new JsonSerializerSettings{ContractResolver = new CamelCasePropertyNamesContractResolver()};
HttpContext.Current.Items["401message"] = JsonConvert.SerializeObject(unAuthorisedResult, Formatting.Indented, jsonSerializerSettings);
}
//Add headers from old response to new response
foreach (var header in response.Headers)
{
newResponse.Headers.Add(header.Key, header.Value);
}
return newResponse;
}
return response;
}
private bool GetInitialAuthorization(HttpRequestMessage request)
{
bool isAuthenticated = false;
try
{
string cookieId = string.Empty;
IEnumerable<CookieHeaderValue> cookies = request.Headers.GetCookies(Constants.COOKIE_BROWSER_NAME);
if (cookies.Any())
{
IEnumerable<CookieState> cookie = cookies.First().Cookies;
if (cookie.Any())
{
var cookieValue = cookie.FirstOrDefault(x => x.Name == Constants.COOKIE_BROWSER_NAME);
if (cookieValue != null)
cookieId = cookieValue.Value.ToLower();
}
}
isAuthenticated = _commonService.IsAuthorized(cookieId);
}
catch (Exception ex)
{
//log error
LogUtility.BuildExceptionMessage(ex);
}
return isAuthenticated;
}
private bool AssertAuthorization(bool initialAuthorizationStatus, HttpRequestMessage request)
{
bool authorizationCheckStatus = true;
//get controller name and action name.
var data = ((request.GetRouteData().Route.DataTokens as System.Web.Http.Routing.HttpRouteValueDictionary));
string actionName = ((System.Web.Http.Controllers.HttpActionDescriptor[])data["actions"])[0].ActionName;
string controllerName = ((System.Web.Http.Controllers.HttpActionDescriptor[])data["actions"])[0].ControllerDescriptor.ControllerName;
List<WebApiControllerAuthorizationSetting> webApiControllerAuthorizationSettings = WebApiAuthorizationSettings.GetWebApiAuthorizationSettings();
var controllerAuthorizationSetting = GetControllerSetting(webApiControllerAuthorizationSettings, controllerName);
if (controllerAuthorizationSetting != null)
{
bool isAuthenticationRequired = controllerAuthorizationSetting.IsAuthorizationRequired;
//if action level settings are available, then the controller settings will be overridden by action level settings
var actionAuthorizationSetting = GetActionSetting(controllerAuthorizationSetting, actionName);
if (actionAuthorizationSetting != null)
{
//check if the action is anonymous. if so, set the roles to anonymous.
isAuthenticationRequired = actionAuthorizationSetting.IsAuthorizationRequired;
}
if (isAuthenticationRequired)
{
if (!initialAuthorizationStatus)
{
authorizationCheckStatus = false;
}
}
}
return authorizationCheckStatus;
}
}
对 /api/profile 的任何请求都需要验证以进行授权检查。在 GetInitialAuthorization() 中,初始授权是根据请求中存在的 cookie 完成的,然后在方法中完成另一项检查: AssertAuthorization(initialAuthorizationStatus, request) 对 WebAPIAuthorization.xml 进行检查以查找存在控制器和动作方法。
对于所有其他 REST API 端点,没有授权。
我想在同一行上为 GraphQL 字段实现这一点。
任何人都可以帮助我在实施此授权政策方面提供一些指导。