この記事では、フィルターとインターセプターが簡単なセキュリティ認証の例の開発の実践を通じてどのように機能するかを理解しています。
多くの記事は、フィルター、インターセプター、リスナーをSpringと関連付けて説明し、フィルター、インターセプター、リスナーはSpringが提供するコンポーネント機能を広く使用していると考えています。
しかし、厳密に言えば、フィルターとリスナーはサーブレットAPIに属し、春とは何の関係もありません。
フィルターがjavax.servlet.filterインターフェイスから継承し、リスナーがjavax.servlet.servletcontextListenerインターフェイスから継承するため、インターセプターのみがorg.springframework.web.servlet.handlerInterceptorインターフェースを継承します。
上記のフローチャートはオンライン情報から参照されており、1つの写真は千語の価値があります。この記事を読んだ後、フィルターとインターセプターの呼び出しプロセスをより深く理解することができます。
1。安全認定設計のアイデア
時々、内部ネットワークと外部ネットワークがAPIを呼び出すと、さまざまな要件のセキュリティ要件があります。多くの場合、外部ネットワークコールAPIのさまざまな制限は、イントラネットでは必要ありません。ただし、ゲートウェイを展開する場合、コストと複雑さの問題により、内部および外部ネットワークによって呼び出されるAPIが一緒に展開される場合があります。
RESTインターフェイスのセキュリティを実現するために、Spring SecurityやShiroなどの成熟したフレームワークを使用して実行できます。
ただし、セキュリティフレームワークはしばしば複雑であるため(Spring Securityをカウントし、約11のコアモジュールがあり、Shiroのソースコードの量も非常に驚くべきものです)。同時に、複雑な構成が導入される場合があります(人々がより楽しく感じることができます)。これは、中小チームの柔軟で迅速な開発、展開、および問題調査を助長しません。
多くのチームは、安全性認定を実現するために独自のホイールを構築しています。この記事のこの簡単な認証の例は、私がいる元工場開発チームを指し、トークンベースのセキュリティ認証サービスと見なすことができます。
一般的なデザインのアイデアは次のとおりです。
1. HTTPリクエストヘッダーをカスタマイズします。 APIが呼び出されるたびに、リクエストヘッダーにトークン値が渡されます。
2。トークンをキャッシュ(Redisなど)に配置し、異なるビジネスとAPIに従って異なるポリシーの有効期限を設定します。
3.トークンは、API呼び出しの頻度を制限し、開発とテストを促進し、異常の緊急処理を促進し、APIを一時的に閉じることさえでき、ホワイトリストやブラックリストを設定できます。
4.外部ネットワーク呼び出しはトークンを送信する必要があります。トークンは、ページを開いたりログインしてトークン書き込み要求ヘッダーを生成するたびに、ユーザーに関連する可能性があります。ページは、Cookieとトークンの有効性を検証します。
Spring Security Frameworkには、認証と承認という2つの概念があります。認証とは、システムにアクセスできるユーザーを指し、認可はユーザーがアクセスできるリソースです。
上記の簡単なセキュリティ認証要件を達成するには、トークンがグローバルに一意であることを確認するために、トークンサービスを独立して作成する必要がある場合があります。カスタムフロージェネレーター、CRM、暗号化と復号化、ログ、API統計、キャッシュなどを含む可能性のあるモジュール。 SMSや電子メールサービスなどのユーザーに関連する一部の公共サービスは、トークンメカニズムを介してセキュリティコールを解決することもできます。
要約すると、この記事の簡単なセキュリティ認証は、実際には、Spring Security Frameworkによって提供された認証と承認とは少し異なります。もちろん、この「安全」治療法は専門家にとって新しいものではありませんが、外部から多くの初心者ユーザーをブロックすることができます。
2。フィルターをカスタマイズします
Similar to Spring MVC, Spring Boot provides many servlet filters (Filters) to use, and it automatically adds some commonly used filters, such as CharacterEncodingFilter (used to handle encoding problems), HiddenHttpMethodFilter (hidden HTTP function), HttpPutFormContentFilter (form form processing), RequestContextFilter (request context), etc. Usually we will also customize Filter to implement some commonログの記録、ログインするかどうか、許可確認などの関数。
1。カスタムリクエストヘッダー
それは非常にシンプルです、リクエストヘッダーにAuthtokenのカスタムリクエストヘッダーを追加します:
@RequestMapping(value = "/getInfobyid"、method = requestmethod.post)@apioperation( "製品IDに基づくクエリ製品情報")@apiimplicitparams({@apiimplictparams(paramtype = "header"、name = "authtoken" = "infult =" getGoodsbygoodsidResponse getGoodsbygoodsid(@RequestHeader String Authtoken、@RequestBody getGoodsbyGoodSidRequestリクエスト){return _goodsapiservice.getGoodsbyGoodsid(リクエスト); } getgoodsbygoodsid@RequestHeaderによって変更されたAuthTokenフィールドは、Swaggerのようなフレームワークの下に表示できます。
呼び出し後、HTTPツールに従ってリクエストヘッダーを確認できます。この記事の例はAuthTokenです(いくつかのフレームワークのトークンとは異なります):
注:多くのHTTPCLIENTツールは、RESTTEMPLATEなどの動的伝送要求ヘッダーをサポートしています。
2。フィルターを実装します
フィルターインターフェイスには、init、dofilter、destoryの3つの方法があります。名前が表示されたら、おそらく彼らの主な用途を知っているでしょう。通常、DoFilterメソッド内でHTTPリクエストを処理するだけです。
パッケージ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.factory.annotation.autowired; import org.springframework.stereepue.component; Import javax.servlet authtokenfilterはフィルターを実装しています{@autowired private authtokenservice authtokenservice; @Override public void init(filterconfig var1)servletexception {} @override public void dofilter(servletrequest request、servletresponse response、filterchainチェーン)をスローします。 string token = req.getheader(appconst.auth_token); bizresult <string> bizresult = authtokenservice.powercheck(token); system.out.println(serializeutil.serialize(bizresult)); if(bizresult.getisok()== true){powerlogger.info( "authトークンフィルターが渡されます"); Chain.dofilter(リクエスト、応答); } else {throw new servletexception(bizresult.getMessage()); }} @Override public void Destroy(){}} authtokenfilter実際の階層の観点からは、より多くの式レイヤーを処理するもののほとんどが処理されることに注意してください。フィルターでデータアクセスレイヤーを直接使用することはお勧めしません。私は1年か2年前に多くの古いアンティークプロジェクトで何度もそのようなコードを見てきましたが、本<< Spring Practical >>にこのように書く前例があります。
3。認定サービス
これが主なビジネスロジックです。サンプルコードは、アイデアを書き留める簡単な方法であり、生産環境で簡単に使用するべきではありません。
パッケージcom.power.demo.service.impl; Import com.power.demo.cache.powercachebuilder; Import com.power.demo.common.bizresult; Import com.power.demo.service.contract.authtokenservice; Import org.springframework.beans.beans.beanwork.bbeanwork.bbeanwork org.springframework.stereotype.component; import org.springframework.util.stringutils; @componentpublic class authtokenserviceimpl authtokenservice {@autowired powercachebuilder cachebuilder; / * *リクエストヘッダートークンが合法かどうかを確認 * System.out.println( "Tokenの値は:" + Token); if(stringutils.isempty(token)== true){bizresult.setfail( "authtoken is empty"); BizResultを返します。 } // BlackList bizResult = checkforbidlist(token); if(bizresult.getisok()== false){return bizresult; } //ホワイトリストの処理bizResult = checkallowlist(token); if(bizresult.getisok()== false){return bizresult; } string key = string.format( "power.authtokenservice。%s"、token); //cachebuilder.set(Key、Token); //cachebuilder.set(Key、token.touppercase()); // cache = cachebuilder.get(key)から存在する文字列をfechtokenするif(stringutils.isempty(expectoken)== true){bizresult.setfail(string.format( "this authtoken:%s"、token)); BizResultを返します。 } //トークンが同じブールのiSequalであるかどうかを比較します= token.equals(exptoken); if(isequal == false){bizresult.setfail(string.format( "Illegal authtoken:%s"、token)); BizResultを返します。 } //何かをしてくださいbizresult; }} authtokenserviceimplここで使用するキャッシュサービスを参照できます。これは、以前の工場での私の経験の要約でもあります。
4.登録フィルター
書くには2つの一般的な方法があります。
(1)@webfilterアノテーションを使用して、フィルターを識別します
@Order(1)@WebFilter(urlpatterns = {"/api/v1/*"、 "/api/v1/userinfo/*"})public class authtokenfilter explentice {@WebFilter Annotationを使用して、 @Order Annotationと組み合わせて @Order Annotationを使用することもできます。 @Orderアノテーションは、フィルタリングの順序を表します。値が小さいほど、最初にそれを実行します。この注文サイズは、プログラミングプロセス中のHTTP要求のライフサイクルを処理するのと同じくらい便利です。もちろん、順序が指定されていない場合、フィルターの順序は追加されたフィルターの順序とは反対に呼ばれ、フィルターの実装は責任チェーンパターンです。
最後に、@servletcomponentscanアノテーションをスタートアップクラスに追加して、正常にカスタムフィルターを使用します。
(2)FilterRegistrationBeanを使用して、フィルター登録をカスタマイズします
この記事では、2番目の実装を使用して、カスタムフィルター登録を実装しています。
パッケージcom.power.demo.controller.filter; Import com.google.common.collect.lists; import org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.web.servlet.filterregristrationbean; import.springframework.nant. org.springframework.context.annotation.configuration; import org.springframework.stereotype.component; import java.util.list;@configuration@componentpublic class restfilterconfig {@autowired private auttokenfilterフィルター; @bean public filterregistrationbean filterregistrationbean(){filterregistrationbean registrationbean = new FilterRegistrationBean();登録bean.setfilter(フィルター); // set(fuzzy)一致するurlリスト<string> urlpatterns = lists.newarraylist(); urlpatterns.add( "/api/v1/goods/*"); urlpatterns.add( "/api/v1/userinfo/*");登録bean.seturlpatterns(urlpatterns);登録bean.setorder(1);登録bean.setEnabled(true); returntationBean; }} restfilterconfigurlpatternsに特に注意してください。属性urlpatternsは、フィルタリングするURLパターンを指定します。このパラメーターは、アクションのフィルター領域にとって非常に重要です。
フィルターを登録し、スプリングブートが起動すると、javax.servlet.filterでBeanを検出すると、フィルターコールチェーンApplicationFilterChainが自動的に追加されます。
APIを呼び出して効果を試してください。
通常、Spring Bootの下でグローバル統合例の例外管理拡張機能GlobalExceptionHandlerをカスタマイズします(上記とはわずかに異なります)。
私の練習によると、フィルターに投げ込まれた例外は、グローバルにユニークな例外管理の強化によって捕まえられ、処理されません。これは、インターセプターインテセプターおよび次の記事で導入されたカスタムAOPインターセプターとは異なります。
この時点で、カスタムフィルターを介して実装された簡単なセキュリティ認証サービスが実行されます。
3。カスタムインターセプター
1.インターセプターを実装します
インターフェイスHandlerInterceptorを継承し、インターセプターを実装します。インターフェイスメソッドは次のとおりです。
PreHandleは、リクエスト実行前に実行されます
POSTHANDLEは、リクエスト実行の終了です
ビューのレンダリングが完了した後、後部が実行されます
パッケージcom.power.demo.controller.interceptor;インポート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.factory.annotation.autowired; import org.springframework.stereepule.component; import org.springframework.web.servlet.handerinterceptor; Import inmoorg.springframework.work.web.serv.serv.servifed.serv.servifew.moeb.serv.servwork javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse;/ * *認証トークンインターセプター * */ @componentpublicクラスAuthtokeninterceptor HandlerInterceptor {@autowired autherservice authtokenservice; / * *リクエストの実行前に実行 * */ @Override public boolean prehandle(httpservletrequest request、httpservletResponse応答、オブジェクトハンドラー)スロー例外{boolean handleresult = false; string token = request.getheader(appconst.auth_token); bizresult <string> bizresult = authtokenservice.powercheck(token); system.out.println(serializeutil.serialize(bizresult)); handleresult = bizresult.getisok(); PowerLogger.info( "Auth Token Token Interctor Interctor Interctor Interctor Interctor Interctor Interceptor Interceptor Interceptor Interceptor Interceptorが合格しました"); } else {throw new Exception(bizresult.getMessage()); } return handleresult; } / * *リクエストの終了execution * * * / @Override public void posthandle(httpservletrequest request、httpservletresponse応答、オブジェクトハンドラー、モデルアンドビューmodelandview)は例外{} / * *レンダリング後に例外をスローしますハンドラー、例外ex)スロー例外{}} authtokeninterceptorこの例では、リクエストが実行される前に、トークンセキュリティ認証を実行することを選択します。
認証サービスは、フィルターに導入されたAuthTokenServiceであり、ビジネスロジックレイヤーが再利用されます。
2。インターセプターを登録します
WebMVCCONFigurationSupportから継承されたInterceptorConfigクラスを定義し、WebMVCCONFigurerAdapterは時代遅れです。
authtokeninterceptorをbean、他の設定インターセプターインターセプトが非常に似ているURLおよびフィルターを塗る:
パッケージ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.stereope.component; org.springframework.web.servlet.config.annotation.defaultservlethandlerconfigurer; Import org.springframework.web.servlet.config.annotation.interceptorregistry; Import org.springframework.web.servlet.config.annotation.Resource.Resource.Resource.Resource.Resource ORG.SPRINGFRAMEWORK.WEB.SERVLET.CONFIG.ANNOTATION.WEBMVCONFIGURATIONSUPPORT; IMPORT JAVA.UTIL.LIST;@Configuration@ComponentPublic InterceptorConfigはWebMVCCONFIGURATIONSUPPORT {// WEBMVCONFIGURERADAPTER IS OUTDSTER "/favicon.ico"; /*** WebMVCConFigurationSupportが継承されている場合、YMLで構成された関連コンテンツが無効になることを発見しました。 * *@param registry */@Override public void addResourceHandlers(resourcehandlerregistry registry){registry.addresourcehandler( "/")。 registry.addresourcehandler( "/static/**")。addresourcelocations( "classpath:/static/"); } / *** Servlet Processingを構成* / @Override public void ConfiguredEfaultServLethandling(defaultServLethLethLerconFigurer configure){configurer.enable(); } @Override public void addInterceptors(interceptorRegistryレジストリ){// set(fuzzy)一致するurlリスト<string> urlpatterns = lists.newarraylist(); urlpatterns.add( "/api/v1/goods/*"); urlpatterns.add( "/api/v1/userinfo/*"); registry.adddinterceptor(authtokeninterceptor())。 Super.AddDINTERCEPTORS(レジストリ); } //インターセプターをbeanとしてbeanを構成に書き込みます}} InterceptorConfigアプリケーションを開始した後、インターフェイスを呼び出すことにより、インターセプターインターセプトの効果を確認できます。グローバルユニファイプされた例外管理GlobalExceptionHandlerは、キャッチした後に次の例外を処理します。
これは、フィルターによって表示されるメインエラーメッセージとほとんど同じですが、スタック情報はより豊富です。
4。フィルターとインターセプターの違い
主な違いは次のとおりです。
1.インターセプターは主にJavaの反射メカニズムに基づいており、フィルターは機能コールバックに基づいています
2。インターセプターはサーブレットコンテナに依存せず、フィルターはサーブレット容器に依存しています
3.インターセプターはアクションリクエストでのみ動作しますが、フィルターはほぼすべてのリクエストで動作できます。
4.インターセプターは、アクションコンテキストと値スタックでオブジェクトにアクセスできますが、フィルターはそれにアクセスできません。
5。アクションのライフサイクル中に、インターセプターを複数回呼び出すことができますが、フィルターはコンテナが初期化されたときに1回しか呼び出されません。
私が言及したいくつかの記事は、「インターセプターはIOCコンテナ内のさまざまな豆を取得できますが、フィルターはできません。これは非常に重要です。インターセプターにサービスを注入すると、ビジネスロジックを呼び出すことができます。」実際の検証の後、これは間違っています。
注:フィルターのトリガー時間はコンテナの後に、サーブレットの前であるため、フィルターがHTTPSERVLETの前であるため、フィルターDOFILTER(ServleTRequest Request、ServleTResponse Response、FilterChain Chain)の入力パラメーターはServleTRequestではなくServleTRequestです。次の図は、フィルターとインターセプターの実行タイミングをより直感的に理解することができます。
DispatcherServletによって渡されたリクエストのみが、インターセプターチェーンが続きます。カスタムサーブレットリクエストは傍受されません。たとえば、カスタマイズされたサーブレットアドレスhttp:// localhost:9090/testServletは、インターセプターによって傍受されません。しかし、どのサーブレットに属していても、フィルターがフィルターのフィルタールールに準拠している限り、フィルターは実行されます。
上記の分析によると、原則を理解することは簡単であり、ASP.NETフィルターでさえ同じです。
問題:より柔軟なセキュリティ認証を実現します
Java Webの下では、カスタムフィルターフィルターまたはインターセプターインターセプターを介して、すべてのAPIのマッチング、1つまたは複数のAPIのマッチングなど、特定のマッチングAPIの安全な認証を実現できますが、このマッチングパターンは開発者に対して比較的フレンドリーではありません。
Annotation + Spelを通じて強力な機能を実現するために、Spring Securityを参照できます。
たとえば、ASP.NETでは、クラスに追加したり、メソッドに適用できる認定機能を使用したり、セキュリティ認証をより動的かつ柔軟に制御できます。
Spring Securityを選択しなかったため、承認と同様の柔軟なセキュリティ認証を実装できます。主な実装技術は、私たちがよく知っているAOPです。
この記事では、AOPメソッドを介してより柔軟な傍受を達成することに関する基本的な知識は言及されません。 AOPに関するその他のトピックは、次の記事で共有されます。
要約します
上記は、編集者があなたに紹介したものです。 Spring Bootは、フィルターとインターセプターを使用して、RESTインターフェイスのシンプルで安全な認証を実現します。私はそれが誰にでも役立つことを願っています。ご質問がある場合は、メッセージを残してください。編集者は、すべての人に時間内に返信します。 wulin.comのウェブサイトへのご支援ありがとうございます!