Implement authorization on Fields using GraphQL.NET and ASP.NET Core 2

为君一笑 提交于 2019-12-11 01:43:25

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!