programing

Windows 인증을 사용하는 WebAPI CORS - 익명 옵션 요청 허용

itmemos 2023. 10. 4. 20:59
반응형

Windows 인증을 사용하는 WebAPI CORS - 익명 옵션 요청 허용

Windows Authentication으로 실행되는 WebAPI 2 REST 서비스가 있습니다.웹사이트와는 별도로 진행되기 때문에 ASP를 이용하여 CORS를 활성화하였습니다.NET CORS NuGet 패키지.내 고객 사이트는 Angular를 사용하고 있습니다.JS.

지금까지 제가 겪은 일은 다음과 같습니다.

  1. 자격증이 설정되어 있지 않아서 CORS 요청이 401을 반송하고 있었습니다.$httpProvider 구성에 자격 증명을 추가하여 해결했습니다.
  2. 그런 다음 자격 증명을 사용할 때 허용되지 않는 와일드카드 오리진으로 EnableCorsAttribute를 설정했습니다.명시적인 오리진 목록을 설정하여 해결합니다.
  3. 이를 통해 GET 요청이 성공할 수 있었지만 POST는 비행 전 요청을 발행했으며 OTIONS 동사를 지원하는 컨트롤러 작업을 만들지 않았습니다.이를 해결하기 위해 메시지 핸들러를 글로벌 옵션 핸들러로 구현했습니다.모든 OPTIONS 요청에 대해 200을 반환하기만 하면 됩니다.완벽하지 않다는 건 알지만 지금은 피들러에서 일하죠

내가 갇혀있는 곳 - 내 Angular preflight calls에 자격 증명이 포함되어 있지 않습니다.이 답변에 따르면, OPTIONS 요청은 익명으로 설계되었기 때문에 이는 설계상입니다.그러나 Windows Authentication(윈도우 인증)이 401로 요청을 중지하고 있습니다.

[익명 허용] 속성을 MessageHandler에 넣으려고 했습니다.내 개발 컴퓨터에서는 작동합니다 - OPTONSE 동사는 인증이 필요하지 않지만 다른 동사는 가능합니다.테스트 서버를 구축하고 배포할 때 OTIONS 요청에 따라 401이 계속 표시됩니다.

Windows 인증을 사용할 때 [익명 허용]을 내 MessageHandler에 적용할 수 있습니까?만약 그렇다면, 어떻게 해야 하는지에 대한 지침이 있습니까?아니면 여기가 잘못된 토끼구멍인가요? 다른 방법을 찾아야 하나요?

업데이트: IIS의 사이트에서 Windows Authentication(윈도우 인증)과 Anonymous Authentication(익명 인증)을 모두 설정하여 작동시킬 수 있었습니다.이로 인해 모든 것이 익명으로 허용되므로 허용을 유지하면서 인증의 전역 필터를 추가했습니다.내 MessageHandler에 익명입니다.

하지만 이건 해킹처럼 느껴집니다.저는 항상 하나의 인증 방법만 사용해야 한다는 것을 이해해 왔습니다(혼합되지 않음).더 좋은 접근 방법이 있다면 들어주시면 감사하겠습니다.

HttpListener와 함께 자체 호스팅을 사용했는데 다음과 같은 솔루션이 효과적이었습니다.

  1. 익명 옵션 요청 허용
  2. 지원 자격 증명이 true로 설정된 CORS 사용
var cors = new EnableCorsAttribute("*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
var listener = appBuilder.Properties["System.Net.HttpListener"] as HttpListener;
if (listener != null)
{
    listener.AuthenticationSchemeSelectorDelegate = (request) => {
    if (String.Compare(request.HttpMethod, "OPTIONS", true) == 0)
    {
        return AuthenticationSchemes.Anonymous;
    }
    else
    {
        return AuthenticationSchemes.IntegratedWindowsAuthentication;
    }};
}

CORS 요청이 다음과 같은 제약 조건(OP의 제약 조건과 매우 유사) 내에서 작동하도록 만들기 위해 한동안 고심했습니다.

  • 모든 사용자를 위한 Windows 인증
  • 익명 인증 불가
  • CORS 비행 전 요청을 전송하지 않는 IE11(또는 적어도 글로벌.asax BeginRequest as OPTONS 요청)과 함께 작동합니다.

최종 구성은 다음과 같습니다.

web.config - 인증되지 않은(익명의) 비행 전 요청 허용(OPTIONS)

<system.web>
    <authentication mode="Windows" />
    <authorization>
        <allow verbs="OPTIONS" users="*"/>
        <deny users="?" />
    </authorization>
</system.web>

global.asax.cs - 다른 도메인의 호출자가 데이터를 받을 수 있는 헤더로 적절하게 응답합니다.

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (Context.Request.HttpMethod == "OPTIONS")
    {
        if (Context.Request.Headers["Origin"] != null)
            Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);

        Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, MaxDataServiceVersion");
        Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");

        Response.End();
    }
}

CORS 활성화

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // all requests are enabled in this example. SupportsCredentials must be here to allow authenticated requests          
        var corsAttr = new EnableCorsAttribute("*", "*", "*") { SupportsCredentials = true };
        config.EnableCors(corsAttr);
    }
}

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
}

이것은 앱 풀 계정을 효과적으로 사칭하기 위해 모든 "OPTIONS" 요청을 허용하는 몇 줄의 코드인 훨씬 더 간단한 해결책입니다.익명을 해제한 상태로 유지하고 일반적인 방식에 따라 CORS 정책을 구성할 수 있지만 다음을 global.asax.cs 에 추가할 수 있습니다.

            protected void Application_AuthenticateRequest(object sender, EventArgs e)
            {
                if (Context.Request.HttpMethod == "OPTIONS" && Context.User == null)
                {
                    Context.User = System.Security.Principal.WindowsPrincipal.Current;
                }
            }

우리 상황에서:

  • 윈도 인증
  • CORS 원점이 여러 개
  • 지원 자격 증명이 true로 설정됨
  • IIS 호스팅

솔루션이 다른 곳에 있다는 것을 확인했습니다.

Web.Config에서는 runAllManagedModulesForAllRequests=true를 추가하기만 하면 되었습니다.

<modules runAllManagedModulesForAllRequests="true">

Application_BeginRequest가 트리거되지 않는 이유에 대한 솔루션을 조사함으로써 이 솔루션에 도달했습니다.

다른 구성은 다음과 같습니다.

Web.Config에서

    <authentication mode="Windows" />
    <authorization>
      <allow verbs="OPTIONS" users="*" />
      <deny users="?"/>
    </authorization>

WebApiConfig에서

        private static string GetAllowedOrigins()
        {
            return ConfigurationManager.AppSettings["CorsOriginsKey"];
        }

        public static void Register(HttpConfiguration config)
        {
            //set cors origins
            string origins = GetAllowedOrigins();
            var cors = new EnableCorsAttribute(origins, "*", "*");
            config.EnableCors(cors);

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
       }

BTW "*" cors origin이 Windows Authentication / Support Credentials = true와 호환되지 않습니다.

https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api#pass-credentials-in-cross-origin-requests

매우 비슷한 방식으로 해결했지만 세부적인 내용을 가지고 oData 서비스에 집중했습니다.

요청을 게시하는 데 필요했기 때문에 IIS에서 익명 인증을 비활성화하지 않았습니다.

Global.aspx 했습니다 에MaxDataServiceVersion인에Access-Control-Allow-Headers)

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if ((Context.Request.Path.Contains("api/") || Context.Request.Path.Contains("odata/")) && Context.Request.HttpMethod == "OPTIONS")
    {
        Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
        Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,MaxDataServiceVersion");
        Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
        Context.Response.End();
    }
} 

그리고.WebAPIConfig.cs

public static void Register(HttpConfiguration config)
{
   // Web API configuration and services
   var cors = new EnableCorsAttribute("*", "*", "*");
   cors.SupportsCredentials = true;
   config.EnableCors(cors);


   config.Routes.MapHttpRoute(
       name: "DefaultApi",
       routeTemplate: "api/{controller}/{id}",
       defaults: new { id = RouteParameter.Optional }
   );
}

및 각도JS콜

$http({
       method: 'POST',
        url: 'http://XX.XXX.XXX.XX/oData/myoDataWS.svc/entityName',
        withCredentials: true,
        headers: {
            'Content-Type': 'application/json;odata=verbose',
            'Accept': 'application/json;odata=light;q=1,application/json;odata=verbose;q=0.5',
            'MaxDataServiceVersion': '3.0'
        },
        data: {
            '@odata.type':'entityName',
            'field1': 1560,
            'field2': 24,
            'field3': 'sjhdjshdjsd',
            'field4':'wewewew',
            'field5':'ewewewe',
            'lastModifiedDate':'2015-10-26T11:45:00',
            'field6':'1359',
            'field7':'5'
        }
    });

데이브,

CORS 패키지를 가지고 장난을 친 후, 이것이 나에게 작동하게 한 이유입니다: [EnableCors(원본: ", 헤더: ", methods: "*, SupportsCredentials=true)]

SupportsCredentials=true를 활성화해야 했습니다.오리진스,머리글 및 메서드가 모두 "*"로 설정되어 있습니다.

필요 없는 경우 IIS에서 익명 인증을 사용하지 않도록 설정합니다.

글로벌 asax에 이를 추가합니다.

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if ((Context.Request.Path.Contains("api/") || Context.Request.Path.Contains("odata/")) && Context.Request.HttpMethod == "OPTIONS")
    {
        Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
        Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
        Context.Response.End();
    }
} 

cors를 활성화하는 경우 다음과 같은 자격 증명 사용도 활성화해야 합니다.

public static void Register(HttpConfiguration config)
{
   // Web API configuration and services
   var cors = new EnableCorsAttribute("*", "*", "*");
   cors.SupportsCredentials = true;
   config.EnableCors(cors);

   // Web API routes
   config.MapHttpAttributeRoutes();

   config.Routes.MapHttpRoute(
       name: "DefaultApi",
       routeTemplate: "api/{controller}/{id}",
       defaults: new { id = RouteParameter.Optional }
   );
}

보시다시피 CORS를 전역적으로 활성화하고 애플리케이션 BeginRequest hook을 사용하여 api(Web Api) 및 odata 요청(사용하는 경우)에 대한 모든 OPTIONS 요청을 인증합니다.

이것은 모든 브라우저에서 잘 작동하며, 클라이언트 측에서는 아래와 같이 xhrFiled with Credentials를 추가해야 합니다.

$.ajax({
    type : method,
    url : apiUrl,
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    async : true,
    crossDomain : true,
    contentType : "application/json",
    data: data ? JSON.stringify(data) : ''
}).....

후크를 사용하지 않는 다른 해결책을 찾으려고 노력하고 있지만 지금까지 성공하지 못하면 web.config 구성을 사용하여 다음과 같은 작업을 수행합니다. 아래 구성 경고가 작동하지 않습니다.

  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <authentication mode="Windows" />
    <authorization>
      <deny verbs="GET,PUT,POST" users="?" />
      <allow verbs="OPTIONS" users="?"/>
    </authorization>
  </system.web>
  <location path="api">
    <system.web>
      <authorization>
        <allow users="?"/>
      </authorization>
    </system.web>
  </location>

웹에서 발견한 다른 솔루션들은 제게 효과가 없거나 너무 까다로워 보였습니다. 결국 더 간단하고 효과적인 솔루션을 생각해냈습니다.

web.config:

<system.web>
    ...
    <authentication mode="Windows" />
    <authorization>
        <deny users="?" />
    </authorization>
</system.web>

프로젝트 속성:

  1. 켜다.Windows Authentication
  2. 끄다Anonymous Authentication

CORS 설정:

[assembly: OwinStartup(typeof(Startup))]
namespace MyWebsite
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(CorsOptions.AllowAll);

이를 위해서는 마이크로소프트가 필요합니다.NUget에서 사용 가능한 Owin.Cors 어셈블리입니다.

각도 초기화:

$httpProvider.defaults.withCredentials = true;

이것이 제 해결책입니다.

전역.asax*

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if(!ListOfAuthorizedOrigins.Contains(Context.Request.Headers["Origin"])) return;

    if (Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.Headers.Remove("Access-Control-Allow-Origin");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
        HttpContext.Current.Response.StatusCode = 200;
        HttpContext.Current.Response.End();
    }

    if (Request.Headers.AllKeys.Contains("Origin"))
    {
        HttpContext.Current.Response.Headers.Remove("Access-Control-Allow-Origin");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
    }
}

언급URL : https://stackoverflow.com/questions/27414487/webapi-cors-with-windows-authentication-allow-anonymous-options-request

반응형