programing

양식 인증: 로그인 페이지로 리디렉션 사용 안 함

oldcodes 2023. 6. 28. 21:57
반응형

양식 인증: 로그인 페이지로 리디렉션 사용 안 함

ASP.NET Forms Authentication을 사용하는 응용 프로그램이 있습니다.대부분 잘 작동하지만 .ashx 파일을 통해 간단한 API에 대한 지원을 추가하려고 합니다.나는 ashx 파일에 선택적 인증(즉, 인증 헤더를 제공하지 않으면 익명으로 작동함)을 원합니다.하지만, 당신이 하는 일에 따라, 나는 특정한 조건에서 인증을 요구하고 싶습니다.

필요한 인증이 제공되지 않으면 상태 코드 401로 응답하는 것이 간단한 문제라고 생각했는데, Forms Authentication 모듈이 이를 가로채고 로그인 페이지로 리디렉션하여 응답하는 것 같습니다. 만약 내가 내은말내, 약가만▁my.ProcessRequest방법은 다음과 같습니다.

public void ProcessRequest(HttpContext context)
{
    Response.StatusCode = 401;
    Response.StatusDescription = "Authentication required";
}

그러면 제가 예상했던 것처럼 클라이언트에서 401 오류 코드를 얻는 대신, 저는 실제로 302 로그인 페이지로 리디렉션됩니다.

일반적인 HTTP 트래픽의 경우, 저는 그것이 얼마나 유용한지 알 수 있지만, 제 API 페이지의 경우, 401이 수정되지 않은 상태로 진행되어 클라이언트 측 호출자가 프로그래밍 방식으로 응답할 수 있기를 바랍니다.

그렇게 할 수 있는 방법이 없을까요?

ASP.NET 4.5가 부울 속성을 추가했습니다.

public void ProcessRequest(HttpContext context)
{
    Response.StatusCode = 401;
    Response.StatusDescription = "Authentication required";
    Response.SuppressFormsAuthenticationRedirect = true;
}

조사를 좀 해본 결과, 양식이AuthenticationModule은 다음에 대한 처리기를 추가합니다.HttpApplicationContext.EndRequest으로 벤트이를 합니다. 핸들러에서 401 상태 코드를 확인하고 기본적으로Response.Redirect(loginUrl)대신.제가 알기로는, 이 행동을 무시할 방법이 없습니다.FormsAuthenticationModule.

결국 제가 피해갈 수 있었던 방법은 그를 무력화시키는 것이었습니다.FormsAuthenticationModuleweb.config 파일:

<authentication mode="None" />

그리고 나서 구현하는 것은Application_AuthenticateEvent본인:

void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (Context.User == null)
    {
        var oldTicket = ExtractTicketFromCookie(Context, FormsAuthentication.FormsCookieName);
        if (oldTicket != null && !oldTicket.Expired)
        {
            var ticket = oldTicket;
            if (FormsAuthentication.SlidingExpiration)
            {
                ticket = FormsAuthentication.RenewTicketIfOld(oldTicket);
                if (ticket == null)
                    return;
            }

            Context.User = new GenericPrincipal(new FormsIdentity(ticket), new string[0]);
            if (ticket != oldTicket)
            {
                // update the cookie since we've refreshed the ticket
                string cookieValue = FormsAuthentication.Encrypt(ticket);
                var cookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName] ??
                             new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue) { Path = ticket.CookiePath };

                if (ticket.IsPersistent)
                    cookie.Expires = ticket.Expiration;
                cookie.Value = cookieValue;
                cookie.Secure = FormsAuthentication.RequireSSL;
                cookie.HttpOnly = true;
                if (FormsAuthentication.CookieDomain != null)
                    cookie.Domain = FormsAuthentication.CookieDomain;
                Context.Response.Cookies.Remove(cookie.Name);
                Context.Response.Cookies.Add(cookie);
            }
        }
    }
}

private static FormsAuthenticationTicket ExtractTicketFromCookie(HttpContext context, string name)
{
    FormsAuthenticationTicket ticket = null;
    string encryptedTicket = null;

    var cookie = context.Request.Cookies[name];
    if (cookie != null)
    {
        encryptedTicket = cookie.Value;
    }

    if (!string.IsNullOrEmpty(encryptedTicket))
    {
        try
        {
            ticket = FormsAuthentication.Decrypt(encryptedTicket);
        }
        catch
        {
            context.Request.Cookies.Remove(name);
        }

        if (ticket != null && !ticket.Expired)
        {
            return ticket;
        }

        // if the ticket is expired then remove it
        context.Request.Cookies.Remove(name);
        return null;
    }
}

사실 그것보다 조금 더 복잡하지만, 기본적으로 저는 구현을 보고 코드를 얻었습니다.FormsAuthenticationModule반사경으로내 구현은 기본 제공되는 것과 다릅니다.FormsAuthenticationModule- 않음으로 가 없다는 에서 .401 - 로그인로리하션지디렉다응없아니습효무과가런도답해않음로.만약 그것이 요구 사항이 된다면, 자동 리디렉션 같은 것을 비활성화하기 위해 컨텍스트에 항목을 넣을 수 있을 것 같습니다.

이것이 모두에게 효과가 있을지는 모르겠지만 IIS7에서는 응답을 호출할 수 있습니다.상태 코드와 설명을 설정한 후()를 종료합니다.이쪽으로, 저 #&$^#@*!FormsAuthenticationModule이 리디렉션하지 않습니다.

public void ProcessRequest(HttpContext context) {
    Response.StatusCode = 401;
    Response.StatusDescription = "Authentication required";
    Response.End();
}

zacharydl의 대답을 조금 더 빌자면, 저는 이것을 제 고민을 해결하기 위해 사용했습니다.AJAX인 경우 모든 요청이 시작될 때 즉시 동작을 억제합니다.

protected void Application_BeginRequest()
{
    HttpRequestBase request = new HttpRequestWrapper(Context.Request);
    if (request.IsAjaxRequest())
    {
        Context.Response.SuppressFormsAuthenticationRedirect = true;
    }
}

저는 그 반응이 어떤지 모릅니다.End()가 효과가 있었습니다.저는 그것을 기꺼이 시도했고, MSDN의 Response를 보았습니다.End(): '페이지 실행을 중지하고 EndRequest 이벤트를 발생시킵니다.'

내 해킹의 가치는 다음과 같습니다.

_response.StatusCode = 401;
_context.Items["401Override"] = true;
_response.End();

그런 다음 Global.cs 에서 EndRequest 핸들러를 추가합니다(Authentication HTTP Module 뒤에 호출됨).

protected void Application_EndRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Items["401Override"] != null)
    {
        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.StatusCode = 401;
    }
}

양식이 401을 가로채고 리디렉션을 수행하는 것이 정확하다는 것을 알게 되었지만, 우리는 또한 그것을 뒤집기 위해 그렇게 할 수 있습니다.

기본적으로 302 로그인 페이지로 리디렉션하여 401로 되돌리는 http 모듈이 필요합니다.

이 작업을 수행하는 단계는 여기에 설명되어 있습니다.

지정된 링크는 WCF 서비스에 대한 것이지만 모든 양식 인증 시나리오에서 동일합니다.

위 링크에서 설명한 대로 http 헤더도 지워야 하지만 원래 응답(즉, 가로채기 전)에 쿠키가 포함되어 있으면 cookie 헤더를 응답에 다시 넣어야 합니다.

저는 이미 틱으로 답이 있다는 것을 알고 있지만 비슷한 문제를 해결하려고 노력하는 동안 이것을 발견했습니다(http://blog.inedo.com/2010/10/12/http-418-im-a-teapot-finally-a-%e2%80%9clegitimate%e2%80%9d-use/) 을 대안으로 사용했습니다).

기본적으로 코드에 있는 HTTP 상태 코드(예: 418)를 반환합니다.WCF 데이터 서비스입니다.

throw new DataServiceException(418, "401 Unauthorized");

다음 모듈에서 합니다.EndRequest401로 코드를 다시 쓰는 이벤트.

HttpApplication app = (HttpApplication)sender;
if (app.Context.Response.StatusCode == 418)
{
    app.Context.Response.StatusCode = 401;
}

브라우저/클라이언트는 올바른 콘텐츠와 상태 코드를 받을 것입니다. 저에게 매우 유용합니다. :)

HTTP 상태 코드 418에 대해 자세히 알고 싶다면 이 질문과 답변을 참조하십시오.

이는 알려진 문제이며, 에 대한 NuGet 패키지 및/또는 소스 코드를 사용할 수 있습니다.

사용하면 재미있는 해킹.NET Framework >= v4.0이지만 < v4.5.반사를 사용하여 액세스 불가능한 값을 설정합니다.SuppressFormsAuthenticationRedirect속성:

// Set property to "true" using reflection
Response
  .GetType()
  .GetProperty("SuppressFormsAuthenticationRedirect")
  .SetValue(Response, true, null);

당신은 지않다니습하설정을 .WWW-Authenticate클라이언트가 양식 인증 대신 HTTP 인증을 수행할 수 없도록 하는 코드의 헤더입니다.경우에는, 는 이우경 401 대신 403 합야다에 않을 것입니다. 이는 다음과 같이 인터셉트되지 않습니다.FormsAuthenticaitonModule.

웹 API를 작동시키기 위해 리다이렉트뿐만 아니라 폼 인증 자체도 피하고 싶은 문제가 있었습니다.api에 대한 위치 태그가 있는 web.config의 항목은 도움이 되지 않았습니다.그래서 Suppress Form을 사용했습니다.AuthenticationRedirect 및 HttpContext.현재의.인증을 건너뛰어 일반적으로 인증을 억제합니다.보낸 사람을 식별하기 위해 헤더에 있는 UserAgent와 같은 추가 인증 단계를 구현하는 것이 좋습니다. 예를 들어 보내는 IP에 대해 확인하거나 요청과 함께 다른 키를 보내는 것이 좋습니다.아래는 Global.asax.cs 에 삽입되어 있습니다.

protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Request.UserAgent == "SECRET-AGENT")
        {
            AppLog.Log("Redirect suppressed");

            HttpApplication context = (HttpApplication)sender;

            context.Response.SuppressFormsAuthenticationRedirect = true;
            HttpContext.Current.SkipAuthorization = true;                
        }
    }

사용자를 로그인 페이지가 아닌 Unauthorized Page로 리디렉션하기 위해 Hack은 Application_EndRequest를 Global에 구현하고 현재 호출된 작업의 임시 리디렉션인 Response Status Code 302를 확인합니다.

protected void Application_EndRequest(object sender, EventArgs e)
    {
        if(HttpContext.Current.Response.StatusCode == 302 && User.Identity.IsAuthenticated)
        {
            HttpContext.Current.Response.Clear();
            HttpContext.Current.Response.Redirect("/UnauthorizedPageUrl");
        }
    }

의 Web.config 파일 내부를 확인합니다.configuration\authentication만약 있다면,forms하위 요소는 a와 함께.loginUrl속성을 제거하고 다시 시도하십시오.

언급URL : https://stackoverflow.com/questions/2839406/forms-authentication-disable-redirect-to-the-login-page

반응형