이 기사는 간단한 보안 인증 예제 개발 관행을 통해 필터 및 인터셉터의 작동 방식을 이해합니다.
많은 기사가 필터, 인터셉터 및 리스너를 봄과 연관시키고, 필터, 인터셉터 및 리스너는 스프링에서 제공하는 널리 사용되는 구성 요소 기능이라고 생각합니다.
그러나 엄격하게 말하면 필터와 청취자는 서블릿 API에 속하며 봄과 관련이 없습니다.
필터는 javax.servlet.filter 인터페이스에서 상속되고 리스너는 javax.servlet.servletcontextlistener 인터페이스에서 상속되므로 인터셉터 만 org.springframework.web.servlet.handlerintercrector 인터페이스를 상속합니다.
위의 흐름도는 온라인 정보에서 참조되며 한 장의 사진은 천 단어의 가치가 있습니다. 이 기사를 읽은 후 필터 및 인터셉터의 호출 과정에 대해 더 깊이 이해할 수 있습니다.
1. 안전 인증 설계 아이디어
때로는 내부 및 외부 네트워크가 API를 호출 할 때 다른 요구 사항에 대한 보안 요구 사항이 있습니다. 대부분의 경우 외부 네트워크 호출 API의 다양한 제한은 인트라넷에서 필요하지 않습니다. 그러나 게이트웨이를 배포 할 때는 비용 및 복잡성 문제로 인해 내부 및 외부 네트워크에서 호출 할 API를 함께 배포 할 수 있습니다.
REST 인터페이스의 보안을 실현하기 위해 Spring Security 또는 Shiro와 같은 성숙한 프레임 워크를 통해 수행 할 수 있습니다.
그러나 보안 프레임 워크가 종종 복잡하기 때문에 (스프링 보안을 계산했으며 약 11 개의 핵심 모듈이 있으며 Shiro의 소스 코드의 양도 매우 놀랍습니다). 동시에, 복잡한 구성이 도입 될 수 있으며 (사람들이 더 즐겁게 느끼게 할 수 있습니까), 이는 중소형 팀의 유연하고 빠른 개발, 배포 및 문제 조사에 도움이되지 않습니다.
많은 팀이 안전 인증을 달성하기 위해 자체 휠을 구축합니다. 이 기사 의이 간단한 인증 사례는 내가있는 이전 공장 개발 팀을 말하며 토큰 기반 보안 인증 서비스로 간주 될 수 있습니다.
일반적인 디자인 아이디어는 다음과 같습니다.
1. HTTP 요청 헤더를 사용자 정의하십시오. API가 호출 될 때마다 요청 헤더에 토큰 값이 전달됩니다.
2. 토큰을 캐시 (예 : Redis)에 놓고 다른 비즈니스 및 API에 따라 다른 정책의 만료 시간을 설정하십시오.
3. 토큰은 화이트리스트 및 블랙리스트를 설정하여 API 호출의 빈도를 제한하고 개발 및 테스트를 용이하게하며 비정상의 비상 취급을 용이하게하며 API를 일시적으로 닫을 수 있습니다.
4. 외부 네트워크 호출은 토큰을 보내야합니다. 토큰은 페이지를 열거나 로그인 할 때마다 토큰 쓰기 요청 헤더를 생성 할 때마다 사용자와 관련 될 수 있습니다. 페이지는 쿠키 및 토큰 등의 유효성을 확인합니다.
Spring Security Framework에는 인증 및 승인 의 두 가지 개념이 있습니다. 인증은 시스템에 액세스 할 수있는 사용자를 말하며 권한은 사용자가 액세스 할 수있는 리소스입니다.
위의 간단한 보안 인증 요구 사항을 달성하려면 토큰이 전 세계적으로 고유한지 확인하기 위해 독립적으로 토큰 서비스를 작성해야 할 수도 있습니다. 사용자 정의 유량 생성기, CRM, 암호화 및 암호 해독, 로그, API 통계, 캐시 등이 포함될 수있는 모듈은 실제로 사용자 (CRM)에 약하게 결합되어 있습니다. 우리가 자주 사용하는 SMS 및 이메일 서비스와 같이 사용자와 관련된 일부 공공 서비스는 토큰 메커니즘을 통해 보안 전화를 해결할 수 있습니다.
요약하면,이 기사의 간단한 보안 인증은 실제로 Spring Security Framework에서 제공하는 인증 및 승인과 약간 다릅니다. 물론,이 "안전"치료 방법은 전문가에게는 새로운 것이 아니지만 외부에서 많은 초보자 사용자를 차단할 수 있습니다.
2. 필터를 사용자 정의하십시오
Spring MVC와 마찬가지로 Spring Boot는 사용할 수있는 많은 서블릿 필터 (필터)를 제공하며, 캐릭터 에코딩 필터 (인코딩 문제를 처리하는 데 사용), HiddenhttpMethodFilter (Hidden HTTP 기능), HTTPPUTFORMContentFilter (httpputformContentFilter), httpputformContentFilter (양식 양식 처리) 등과 같은 일반적으로 사용되는 필터를 자동으로 추가합니다. 필터링 로그 기록, 로그인 여부 결정, 권한 확인 등과 같은 몇 가지 공통 기능을 구현합니다.
1. 사용자 정의 요청 헤더
매우 간단합니다. 요청 헤더에 사용자 정의 요청 헤더를 추가하십시오.
@requestmapping (value = "/getinfobyid", method = requestmethod.post) @apioperation ( "제품 ID를 기반으로 한 쿼리 제품 정보"@apiimplicitparams ({@apiimplicitpepe = "header", name = "authtoken", required = "valueToken")))). getGoodSbyGoodSidResponse getGoodSbyGoodSid (@requestheader String authtoken, @requestbody getGoodsByGoodSidRequest 요청) {return _goodSapiserVice.getGoodSbyGoodSid (요청); } getGoodSbyGoodSid@requestheader로 수정 된 Authtoken 필드는 Swagger와 같은 프레임 워크 아래에 표시 될 수 있습니다.
호출 후 HTTP 도구에 따라 요청 헤더를 볼 수 있습니다. 이 기사의 예는 Authtoken입니다 (일부 프레임 워크의 토큰과 다름) :
참고 : 많은 httpclient 도구는 Resttemplate와 같은 동적 전송 요청 헤더를 지원합니다.
2. 필터를 구현하십시오
필터 인터페이스에는 3 가지 방법, 즉 Init, Dofilter 및 Detory가 있습니다. 이름을 보면 아마도 그들의 주요 용도를 알게 될 것입니다. 일반적으로 Dofilter 방법 내에서 HTTP 요청을 처리하면됩니다.
package com.power.demo.controller.filter; import com.power.demo.common.appconst; import com.power.demo.common.bizresult; import com.power.demo.service.contract.authtokenservice; import com.power.demo.util.powerlogger; com.power.demo.util.serializeutil; import org.springframework.beans.beans.annotation.autowired; import org.spramework.stereotyp.component; import javax.servlet.*; import javax.servlet.http.htttp.htttp.httperportrequest;@java.io.oi.oi.oi.compontemente; authtokenfilter는 필터 {@autowired private authtokenservice authtokenservice; @override public void init (FilterConfig var1)는 servletexception {} @override public void dofilter (servletrequest 요청, servletreponse 응답, 필터 체인 체인)를 ioxception, servletexception {httpservletrequest req = (httpervletrequest) 요청; String token = req.getheader (AppConst.auth_token); bizresult <string> bizresult = authtokenservice.powercheck (토큰); System.out.println (Serializeutil.serialize (bizresult)); if (bizresult.getisok () == true) {powerLogger.info ( "Auth Token 필터가 통과"); Chain.dofilter (요청, 응답); } else {Throw New ServleTeXception (bizresult.getMessage ()); }} @override public void destroy () {}} authtokenfilter실제 계층 구조의 관점에서 더 많은 표현층을 처리하는 대부분의 것들이 처리됩니다. 필터에서 데이터 액세스 계층을 직접 사용하는 것이 좋습니다. 나는 1 년 또는 2 년 전에 많은 오래된 골동품 프로젝트에서 그러한 코드를 여러 번 보았지만, 책 << Spring Explication >>에 이런 식으로 글을 쓰는 선례가 있습니다.
3. 인증 서비스
이것이 주요 비즈니스 논리입니다. 샘플 코드는 아이디어를 작성하는 간단한 방법 일 뿐이며 프로덕션 환경에서 쉽게 사용해서는 안됩니다.
package com.power.demo.service.impl; import com.power.demo.cache.powercachebuilder; import com.power.demo.demo.common.bizresult; import com.power.demo.service.contract.authtokenservice; import 또는 org.spramework.beans.foatoration org.springframework.stereotype.component; import org.springframework.util.stringutils; @componentpublic class authtokenserviceimpl empertokenservice {@autowired private cachebuilder cachebuilder; / * * 요청 헤더 토큰이 합법적인지 확인 */ @override public bizresult <string> powerCheck (String Token) {bizresult <string> bizresult = new Bizresult <> (true, "verification wased"); System.out.println ( "토큰의 가치는" + 토큰); if (stringUtils.isempty (Token) == true) {bizresult.setfail ( "Authtoken is Emption"); Bizresult를 반환; } // 블랙리스트 처리 Bizresult = CheckForbidList (토큰); if (bizresult.getisok () == false) {return bizresult; } // 화이트리스트 Bizresult 프로세싱 = Checkallowlist (토큰); if (bizresult.getisok () == false) {return bizresult; } string key = string.format ( "power.authtokenservice.%s", 토큰); //cachebuilder.set(key, Token); //cachebuilder.set(key, token.touppercase ()); // cache = cachebuilder.get (key)에서 존재하는 string이 존재합니다. if (stringUtils.isempty (excienttoken) == true) {bizresult.setfail (string.format ( "this authtoken :%s", token)); Bizresult를 반환; } // 토큰이 동일한 부울 isequal = token.equals (기존)인지 비교합니다. if (isequal == false) {bizresult.setfail (String.format ( "불법 인 Authtoken :%s", Token)); Bizresult를 반환; } // 무언가를 반환합니다 Bizresult; }} authtokenserviceimpl여기에서 사용하는 캐시 서비스를 참조 할 수 있으며, 이는 이전 공장에서의 내 경험을 요약 한 것입니다.
4. 필터 등록
글을 쓰는 두 가지 일반적인 방법이 있습니다.
(1) @WebFilter 주석을 사용하여 필터를 식별하십시오
@Order (1) @WebFilter (urlpatterns = { "/api/v1/goods/*", "/api/v1/userInfo/*"}) public class authtokenfilter emplements 필터 {@WebFilter 주석을 사용하여 @Order 주석과 함께 @Order 주석을 사용할 수도 있습니다. @Order 주석은 필터링 순서를 나타냅니다. 값이 작을수록 먼저 더 많이 실행합니다. 이 주문 크기는 프로그래밍 프로세스 중에 HTTP 요청의 수명주기를 처리하는 것만 큼 유용합니다. 물론 순서가 지정되지 않은 경우 필터의 순서를 추가 필터의 순서와 반대라고하며 필터의 구현은 책임 체인 패턴입니다.
마지막으로 @ServletComponentScan 주석을 시작 클래스에 추가하여 사용자 정의 필터를 정상적으로 사용하십시오.
(2) 필터 등록 빈을 사용하여 필터 등록을 사용자 정의하십시오
이 기사는 두 번째 구현을 사용하여 사용자 정의 필터 등록을 구현합니다.
package com.power.demo.controller.filter; import com.google.common.collect.lists; import org.springframework.beans.bean.annotation.autowired; import org.springframework.boot.web.servlet.filterregistrationbean; import org.spring.spring org.springframework.context.annotation.configuration; import org.springframework.stereotyp.component; import java.util.list;@configuration@componentpublic class restfilterconfig {@autowired private authokenfilter 필터; @bean public filterregistrationbean filterregistrationBean () {filterRegistrationBean registrationBean = new FilterRegistrationBean (); registrationBean.setFilter (필터); // 세트 (퍼지) 일치 URL 목록 <String> urlPatterns = lists.newarrayList (); urlpatterns.add ( "/api/v1/goods/*"); urlpatterns.add ( "/api/v1/userinfo/*"); registrationbean.seturlpatterns (urlpatterns); 등록 비안. 세터 (1); registrationBean.setEnabled (true); 반품 등록 비; }} restFilterConfigurlpatterns에 특별한주의를 기울이십시오. 속성 urlpatterns는 필터링 될 URL 패턴을 지정합니다. 이 매개 변수는 필터 동작 영역에 큰 의미가 있습니다.
레지스터 필터 및 스프링 부팅이 시작되면 javax.servlet.filter로 Bean을 감지 할 때 필터 호출 체인 ApplicationFilterChain을 자동으로 추가합니다.
효과를 시도하려면 API에 전화하십시오.
일반적으로 스프링 부팅에서 글로벌 통합 예외 관리 향상 GlobalExceptionAndler를 사용자 정의합니다 (위와 약간 다릅니다).
내 연습에 따르면, 필터에 던져진 예외는 전 세계적으로 고유 한 예외 관리 향상에 의해 잡히지 않고 처리되지 않습니다. 이는 인터셉터 정관 및 다음 기사에 소개 된 사용자 정의 AOP 인터셉터와 다릅니다.
이 시점에서 사용자 지정 필터를 통해 구현 된 간단한 보안 인증 서비스가 수행됩니다.
3. 사용자 정의 인터셉터
1. 인터셉터를 구현하십시오
인터페이스 핸들러 인터셉터를 상속하고 인터셉터를 구현하십시오. 인터페이스 방법은 다음과 같습니다.
사전 핸들은 요청 실행 전에 실행됩니다
Posthandle은 요청 실행의 끝입니다
뷰 렌더링이 완료된 후에 후속 조치가 실행됩니다.
package com.power.demo.controller.interceptor; import com.power.demo.common.appconst; import com.power.demo.common.bizresult; import com.power.demo.service.contract.authtokenservice; import com.power.demo.util.powerlogger; com.power.demo.util.serializeutil; import org.springframework.beans.beans.annotation.autowired; import org.spramframework.stereotyp.component; import org.springframework.web.servlet.handlerinterceptor; import org.springframework.web.servlet.modview; javax.servlet.http.httpertrequest; import javax.servlet.http.htttp.httpervletresponse;/ * * 인증 토큰 인터셉터 * */ @componentpublic class authtokeninterceptor handlerinterceptor {@autow private authercenservice authtokenservice; / * * 요청 전에 실행하기 전에 실행 */ @override public boolean prehandle (httpservletrequest 요청, httpservletresponse 응답, 개체 핸들러) 예외 {boolean handleresult = false; String token = request.getheader (AppConst.auth_token); bizresult <string> bizresult = authtokenservice.powercheck (토큰); System.out.println (Serializeutil.serialize (bizresult)); handleresult = bizresult.getisok (); PowerLogger.info ( "인증 토큰 인터셉터 인터셉터 인터셉터 인터셉터 인터셉터 인터셉터 인터셉터 인터셉터 인터셉터가 통과했다"); } else {Throw New Exception (vizresult.getMessage ()); } 반환 처리기; } / * * 요청은 실행 종료 * / @override public void posthandle (httpservletrequest 요청, httpservletResponse 응답, 객체 핸들러, ModelAndView ModelAndView)이 예외 {} / * * 실행 후 렌더링이 완료된 후 * / @Override public void responce (httpservletretrespronse, httppestrescronce, htpservletretrospons 객체 핸들러, 예외 Ex)는 예외 {}} authtokeninterceptor를 던집니다이 예에서는 요청이 실행되기 전에 토큰 보안 인증을 수행하도록 선택합니다.
인증 서비스는 필터에 도입 된 AuthTokenService이며 비즈니스 로직 계층이 재사용됩니다.
2. 인터셉터를 등록하십시오
WebMvcConfigUrationSupport에서 상속 된 InterceptorConfig 클래스를 정의하고 WebMVCConfigurerAdapter가 구식입니다.
authtokeninterceptor를 Bean으로 주입하고 다른 설정 인터셉터 인터셉트가 매우 유사하다는 URL 및 필터.
package com.power.demo.controller.interceptor; import com.google.common.collect.lists; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.component; org.springframework.web.servlet.config.annotation.defaultservlethandlerconfigurer; import org.springframework.web.servlet.config.annotation.interceptorregistry; import org.spramework.web.servlet.config.annotation.resourcerepity; org.springframework.web.servlet.config.annotation.webmvcconfigurationsupport; import java.util.list;@componentpublic class interceptorconfig Extends WebMvcConfigUrationsUpport {// webMvcConfigerAdApter는 개인 정적 정적 최종 strated favicon_URDATION FAVICONFIGURERADAPTER입니다. "/favicon.ico"; /*** WebMvcConfigUrationSupport가 상속되면 YML로 구성된 관련 컨텐츠가 유효하지 않다는 것을 발견했습니다. * *@param registry */@override public void addresourcehandlers (resourceHandlerRegistry registry) {registry.AddresOURCEHANDLER ( "/"). addResourcelOcations ( "/**"); registry.addresourceHandler ( "/static/**"). addResourcelocations ( "classPath :/static/"); } / *** 서블릿 처리 구성* / @override public void configuredefaultservleThandling (defaultservleThandLerConfigurer configure) {configurer.enable (); } @override public void addinterceptors (interceptorregistry registry) {// set (fuzzy) 일치하는 URL 목록 <string> urlpatterns = lists.newarrayList (); urlpatterns.add ( "/api/v1/goods/*"); urlpatterns.add ( "/api/v1/userinfo/*"); registry.addinterceptor (AuthTokenInterceptor ()). AddPathPatterns (urlpatterns) .excludepathpatterns (favicon_url); super.addinternceptors (레지스트리); } // 인터셉터를 콩으로 구성 @bean public authtokeninterceptor authtokeninterceptor () {return new Authtokeninterceptor (); }} interceptorConfig응용 프로그램을 시작한 후 인터페이스를 호출하여 인터셉터 차단 효과를 볼 수 있습니다. Global Unified Exception Management Globalexception Handler를 잡은 후 다음과 같은 예외를 처리합니다.
필터에 표시된 기본 오류 메시지와 거의 동일하지만 스택 정보는 더 풍부합니다.
4. 필터와 인터셉터의 차이
주요 차이점은 다음과 같습니다.
1. 인터셉터는 주로 Java의 반사 메커니즘을 기반으로하며 필터는 기능 콜백을 기반으로합니다.
2. 인터셉터는 서블릿 컨테이너에 의존하지 않으며 필터
3. 인터셉터는 작업 요청에 대해서만 작동 할 수 있지만 필터는 거의 모든 요청에서 작동 할 수 있습니다.
4. 인터셉터는 동작 컨텍스트 및 값 스택에서 객체에 액세스 할 수 있지만 필터는 액세스 할 수 없습니다.
5. 동작의 수명주기 동안 인터셉터를 여러 번 호출 할 수있는 반면, 컨테이너가 초기화 될 때 필터는 한 번만 호출 할 수 있습니다.
내가 언급 한 일부 기사는 "인터셉터는 IOC 컨테이너에서 다양한 콩을 얻을 수 있지만 필터는 할 수 없습니다. 이것은 매우 중요합니다. 인터셉터에 서비스를 주입하면 비즈니스 로직을 호출 할 수 있습니다." 실제 검증 후 이것은 잘못되었습니다.
참고 : 필터의 트리거링 시간은 컨테이너 후 및 서블릿 이전에 이루어 지므로 필터가 httpservlet 전에 필터가 httpservletrequest가 아닌 필터 Dofilter (Servletrequest 요청, Servletreponse 응답, 필터 체인 체인)의 입력 매개 변수는 ServletRequest입니다. 다음 수치는 필터 및 인터셉터의 실행 타이밍에 대한보다 직관적 인 이해를 제공 할 수 있습니다.
DispatcherServlet을 통과 한 요청 만 인터셉터 체인이 이어집니다. 맞춤형 서블릿 요청은 가로 채지 않습니다. 예를 들어, 우리의 맞춤형 서블릿 주소 http : // localhost : 9090/testservlet는 인터셉터에 의해 차단되지 않습니다. 그러나 어떤 서블릿에 속하든 필터는 필터의 필터 규칙을 준수하는 한 필터가 실행됩니다.
위의 분석에 따르면 원칙을 이해하는 것은 간단 할 것이며 ASP.NET 필터조차도 동일합니다.
문제 :보다 유연한 보안 인증을 달성하십시오
Java 웹에서 사용자 정의 필터 필터 또는 인터셉터 인터셉터를 통해 모든 API와 일치하는 특정 API와 같은 특정 일치 API의 안전한 인증을 달성 할 수 있지만 때로는이 일치 패턴이 개발자에게 비교적 친숙하지 않습니다.
우리는 주석 + spel을 통해 강력한 기능을 달성하기 위해 Spring Security를 참조 할 수 있습니다.
예를 들어, ASP.NET에서는 종종 공인 된 기능을 사용하여 클래스에 추가하거나 메소드에 적용 할 수 있으며 보안 인증을보다 동적으로 유연하게 제어 할 수 있습니다.
우리는 Spring Security를 선택하지 않았으므로 승인과 유사한 유연한 보안 인증을 구현할 수 있습니다. 주요 구현 기술은 우리가 익숙한 AOP입니다.
이 기사에서는 AOP 방법을 통한보다 유연한 차단을 달성한다는 기본 지식은 언급되지 않습니다. AOP에 대한 더 많은 주제가 다음 기사에서 공유됩니다.
요약
위는 편집자가 당신에게 소개 한 것입니다. Spring Boot는 필터와 인터셉터를 사용하여 REST 인터페이스의 간단하고 안전한 인증을 달성합니다. 모든 사람에게 도움이되기를 바랍니다. 궁금한 점이 있으면 메시지를 남겨 주시면 편집자가 제 시간에 모든 사람에게 답장을 드리겠습니다. Wulin.com 웹 사이트를 지원해 주셔서 대단히 감사합니다!