使用GraphQL.NET和ASP.NET Core 2在字段上实现授权

时间:2018-12-02 13:57:19

标签: c# asp.net-core-2.0 graphql-dotnet

我有一个使用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字段实现此功能。

任何人都可以在实施此授权政策方面为我提供一些指导。

0 个答案:

没有答案