问题
I have a existing REST API developed using ASP.NET WEB API 2 where the authorization is handled by storing all the controller name and action method details in a xml file.
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>
Code:
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;
}
}
Any request comes for /api/profile needs to validated for authorization check. In the GetInitialAuthorization() , the initial authorization is done based on the cookie present in the request and from there on one more check is done at method: AssertAuthorization(initialAuthorizationStatus, request) where a check against WebAPIAuthorization.xml is done to find the presence of controller and action method.
For all other REST API endpoints there is no authorization.
I want to implement this for GraphQL fields on the same lines.
Can anyone help me with some guidance in implementing this authorization policy.
来源:https://stackoverflow.com/questions/53580954/implement-authorization-on-fields-using-graphql-net-and-asp-net-core-2