61.2. 컨테이너 요청 필터
61.2.1. 개요
이 섹션에서는 서버( 컨테이너) 측에서 들어오는 요청 메시지를 가로채는 데 사용되는 컨테이너 요청 필터 를 구현하고 등록하는 방법을 설명합니다. 컨테이너 요청 필터는 서버 측에서 헤더를 처리하는 데 자주 사용되며, 일반 요청 처리(즉, 호출된 특정 리소스 메서드와 독립적인 처리)에 사용할 수 있습니다.
또한 컨테이너 요청 필터는 두 개의 개별 확장 포인트인 PreMatchContainerRequest
(리소스 일치 단계 이전) 및 ContainerRequest
(리소스 일치 단계 이후)에 설치할 수 있기 때문에 특별한 케이스의 일부입니다.
61.2.2. ContainerRequestFilter 인터페이스
javax.ws.rs.container.ContainerRequestFilter
인터페이스는 다음과 같이 정의됩니다.
// Java ... package javax.ws.rs.container; import java.io.IOException; public interface ContainerRequestFilter { public void filter(ContainerRequestContext requestContext) throws IOException; }
ContainerRequestFilter
인터페이스를 구현하면 서버 측에서 다음 확장 포인트 중 하나에 대한 필터를 생성할 수 있습니다.
-
PreMatchContainerRequest
-
ContainerRequest
61.2.3. ContainerRequestContext interface
ContainerRequestFilter
의 필터
메서드는 들어오는 요청 메시지 및 관련 메타데이터에 액세스하는 데 사용할 수 있는 javax.ws.rs.container.ContainerRequestContext
의 단일 인수를 수신합니다. ContainerRequestContext
인터페이스는 다음과 같이 정의됩니다.
// Java ... package javax.ws.rs.container; import java.io.InputStream; import java.net.URI; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map; import javax.ws.rs.core.Cookie; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.UriInfo; public interface ContainerRequestContext { public Object getProperty(String name); public Collection getPropertyNames(); public void setProperty(String name, Object object); public void removeProperty(String name); public UriInfo getUriInfo(); public void setRequestUri(URI requestUri); public void setRequestUri(URI baseUri, URI requestUri); public Request getRequest(); public String getMethod(); public void setMethod(String method); public MultivaluedMap getHeaders(); public String getHeaderString(String name); public Date getDate(); public Locale getLanguage(); public int getLength(); public MediaType getMediaType(); public List getAcceptableMediaTypes(); public List getAcceptableLanguages(); public Map getCookies(); public boolean hasEntity(); public InputStream getEntityStream(); public void setEntityStream(InputStream input); public SecurityContext getSecurityContext(); public void setSecurityContext(SecurityContext context); public void abortWith(Response response); }
61.2.4. PreMatchContainerRequest 필터에 대한 샘플 구현
PreMatchContainerRequest
확장 지점에 대한 컨테이너 요청 필터(즉, 리소스 일치 전에 필터가 실행되는 경우) ContainerRequestFilter
인터페이스를 구현하는 클래스를 정의하려면 @PreMatching
주석( PreMatchContainerRequest
확장 지점 선택)으로 클래스에 주석을 답니다.
예를 들어 다음 코드는 우선순위가 20인 PreMatchContainerContainerRequest
확장 지점에 설치된 간단한 컨테이너 요청 필터의 예를 보여줍니다.
// Java package org.jboss.fuse.example; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.annotation.Priority; import javax.ws.rs.ext.Provider; @PreMatching @Priority(value = 20) @Provider public class SamplePreMatchContainerRequestFilter implements ContainerRequestFilter { public SamplePreMatchContainerRequestFilter() { System.out.println("SamplePreMatchContainerRequestFilter starting up"); } @Override public void filter(ContainerRequestContext requestContext) { System.out.println("SamplePreMatchContainerRequestFilter.filter() invoked"); } }
61.2.5. ContainerRequest 필터에 대한 샘플 구현
ContainerRequest
확장 포인트(즉, 리소스 일치 후 필터가 실행되는 컨테이너 요청 필터)를 구현하려면 @PreMatching
주석 없이 ContainerRequestFilter
인터페이스 를 구현하는 클래스를 정의합니다.
예를 들어 다음 코드는 우선순위가 30인 ContainerRequest
확장 지점에 설치된 간단한 컨테이너 요청 필터의 예를 보여줍니다.
// Java package org.jboss.fuse.example; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.ext.Provider; import javax.annotation.Priority; @Provider @Priority(value = 30) public class SampleContainerRequestFilter implements ContainerRequestFilter { public SampleContainerRequestFilter() { System.out.println("SampleContainerRequestFilter starting up"); } @Override public void filter(ContainerRequestContext requestContext) { System.out.println("SampleContainerRequestFilter.filter() invoked"); } }
61.2.6. ResourceInfo 삽입
ContainerRequest
확장 포인트 (즉, 리소스 일치가 발생한 후 ) ResourceInfo
클래스를 삽입하여 일치하는 리소스 클래스 및 리소스 메서드에 액세스할 수 있습니다. 예를 들어 다음 코드는 ResourceInfo
클래스를 ContainerRequestFilter
클래스의 필드로 삽입하는 방법을 보여줍니다.
// Java package org.jboss.fuse.example; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.ext.Provider; import javax.annotation.Priority; import javax.ws.rs.core.Context; @Provider @Priority(value = 30) public class SampleContainerRequestFilter implements ContainerRequestFilter { @Context private ResourceInfo resinfo; public SampleContainerRequestFilter() { ... } @Override public void filter(ContainerRequestContext requestContext) { String resourceClass = resinfo.getResourceClass().getName(); String methodName = resinfo.getResourceMethod().getName(); System.out.println("REST invocation bound to resource class: " + resourceClass); System.out.println("REST invocation bound to resource method: " + methodName); } }
61.2.7. 호출 중지
컨테이너 요청 필터의 적합한 구현을 생성하여 서버 측 호출을 중단할 수 있습니다. 일반적으로 이 기능은 서버 측에서 보안 기능을 구현하는 데 유용합니다. 예를 들어 인증 기능 또는 권한 부여 기능을 구현합니다. 들어오는 요청이 성공적으로 인증되지 않으면 컨테이너 요청 필터 내에서 호출을 중단할 수 있습니다.
예를 들어 다음 사전 일치 기능은 URI의 쿼리 매개 변수에서 사용자 이름과 암호를 추출하고 인증 방법을 호출하여 사용자 이름과 암호 자격 증명을 확인합니다. 인증에 실패하면 ContainerRequestContext
개체에서 abortWith
를 호출하여 호출이 중단되고 클라이언트에 반환되는 오류 응답을 전달합니다.
// Java package org.jboss.fuse.example; import javax.annotation.Priority; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import javax.ws.rs.ext.Provider; @PreMatching @Priority(value = 20) @Provider public class SampleAuthenticationRequestFilter implements ContainerRequestFilter { public SampleAuthenticationRequestFilter() { System.out.println("SampleAuthenticationRequestFilter starting up"); } @Override public void filter(ContainerRequestContext requestContext) { ResponseBuilder responseBuilder = null; Response response = null; String userName = requestContext.getUriInfo().getQueryParameters().getFirst("UserName"); String password = requestContext.getUriInfo().getQueryParameters().getFirst("Password"); if (authenticate(userName, password) == false) { responseBuilder = Response.serverError(); response = responseBuilder.status(Status.BAD_REQUEST).build(); requestContext.abortWith(response); } } public boolean authenticate(String userName, String password) { // Perform authentication of 'user' ... } }
61.2.8. 서버 요청 필터 바인딩
서버 요청 필터(즉, Apache CXF 런타임에 설치)를 바인딩 하려면 다음 단계를 수행합니다.
다음 코드 조각에 표시된 대로 컨테이너 요청 필터 클래스에
@Provider
주석을 추가합니다.// Java package org.jboss.fuse.example; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.ext.Provider; import javax.annotation.Priority; @Provider @Priority(value = 30) public class SampleContainerRequestFilter implements ContainerRequestFilter { ... }
컨테이너 요청 필터 구현이 Apache CXF 런타임에 로드되면 REST 구현에서 로드된 클래스를 자동으로 검사하여
@Provider
주석(검색 단계)으로 표시된 클래스를 검색합니다.XML에서 JAX-RS 서버 엔드포인트를 정의할 때(예: 18.1절. “JAX-RS Server 엔드 포인트 구성”참조),
jaxrs:providers
요소의 공급자 목록에 server request 필터를 추가합니다.<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" ... > ... <jaxrs:server id="customerService" address="/customers"> ... <jaxrs:providers> <ref bean="filterProvider" /> </jaxrs:providers> <bean id="filterProvider" class="org.jboss.fuse.example.SampleContainerRequestFilter"/> </jaxrs:server> </blueprint>
참고이 단계는 Apache CXF의 비표준 요구 사항입니다. JAX-RS 표준에 따라 엄밀히 말하면
@Provider
주석은 필터를 바인딩하는 데 필요한 모든 것이어야 합니다. 그러나 실제로는 표준 접근 방식은 다소 무독하며 많은 라이브러리가 대규모 프로젝트에 포함될 때 번들링 공급자로 이어질 수 있습니다.