序文
SpringCloudを使用してMicroserviceアーキテクチャを備えた分散システムを構築する場合、OAUTH2.0は認証の業界標準です。 Spring Security OAUTH2は、Spring Cloud/Spring Boot環境でのOAUTH2.0の使用をサポートするための完全なソリューションセットも提供し、すぐにボックスコンポーネントを提供します。ただし、開発プロセス中に、Spring Security OAuth2のコンポーネントが特に包括的であるため、拡張ソリューションを拡張するのが非常に不便であるか、以下などの拡張ソリューションを直接指定することは非常に不便であることがわかります。
これらのシナリオに直面する場合、Spring Security OAUTH2に慣れていない多くの人々が開始できないことが期待されています。上記のシナリオ要件に基づいて、SMS検証コードログインとサードパーティのログインをエレガントに統合する方法、およびエレガントに統合されたと見なす方法は?次の要件があります。
上記の設計要件に基づいて、記事の上記の要件を満たすために一連の統合ログイン認証コンポーネントを開発する方法を詳細に紹介します。
この記事を読むOAUTH2.0認定システム、スプリングブート、スプリングスセキュリティ、スプリングクラウド、その他の関連知識について知っておく必要があります
アイデア
Spring Security OAuth2の認証プロセスを見てみましょう。
このプロセスでは、多くのエントリポイントはありません。統合ログインのアイデアは次のとおりです。
このプロセスにアクセスした後、基本的にサードパーティのログインをエレガントに統合できます。
成し遂げる
アイデアを導入した後、次のコードはそれを実装する方法を示しています。
最初のステップは、ログイン要求をインターセプトするインターセプターを定義することです
/** * @author liqiu * @date 2018-3-30 **/ @componentpublic classauthenticationfilter extends genericfilterbean explments applicationcontextaware {private static final string auth_type_parm_name = "auth_type"; private static final string oauth_token_url = "/oauth/token";プライベートコレクション<IntegrationAuthenticator> Authenticators; private ApplicationContext ApplicationContext; private requestMatcher requestMatcher; public IntegrationAuthenticationFilter(){this.RequestMatcher = new orrequestMatcher(new antpathRequestMatcher(oauth_token_url、 "get")、new antpathrequestmatcher(oauth_token_url、 "post")); } @Override public void dofilter(servletrequest servletrequest、servletResponse servletResponse、filterchain filterchain)IoException、servletexception {httpservletrequest =(httpservletrequest)servletrequest; httpservletResponse応答=(httpservletResponse)servletResponse; if(requestmatcher.matches(request)){//統合ログイン情報統合統合統合authentication = new IntegrationAuthentication(); IntegrationAuthentication.setAuthType(request.getParameter(auth_type_parm_name)); IntegrationAuthentication.setAuthParameters(request.getParametermap()); IntegrationAuthenticationContext.set(IntegrationAuthentication); try {// preprocessing this.prepare(IntegrationAuthentication); filterchain.dofilter(リクエスト、応答); // this.completeの後処理(IntegrationAuthentication); }最後に{IntegrationAuthenticationContext.Clear(); }} else {filterchain.dofilter(request、response); }} / *** preprocessing* @param IntegrationAuthentication* / private void prepare(IntegrationAuthentication IntegrationAuthentication){// Lazy Loading Authicator if(this.Authenticators == null){同期(This){Map <String、IntegrationAuthenticator> IntegrationAuthenticatormap = ApplicationContext.getBeansofType(IntegrationAuthenticator.class); if(IntegrationAuthenticAtormap!= null){this.authenticators = IntegrationAuthenticatormap.values(); }}} if(this.authenticators == null){this.authenticators = new ArrayList <>(); } for(IntegrationAuthenticator Authenticator:Authenticators){if(Authenticator.support(IntegrationAuthentication)){Authenticator.Prepare(IntegrationAuthentication); }}} / *** post-processing* @param IntegrationAuthentication* / private void Complete(IntegrationAuthentication IntegrationAuthentication){for(IntegrationAuthenticator認証:認証){if(authenticator.support(IntegrationAuthentication)){authertication(IntegrationAuthentication); }}} @Override public void setApplicationContext(applicationContext applicationContext)throws beansexception {this.applicationContext = applicationContext; }}このクラスでは、作業の2つの部分が主に完了します。1。パラメーターに従って現在の認証タイプを取得します。2。
ステップ2:インターセプターをインターセプトチェーンに入れます
/** * @author liqiu * @date 2018-3-7 **/ @configuration @enableauthorizationserverpublic class authorationserverConfiguration authorationserverconfigurerAdapter {@autowired private redisconnectionfactory redisconnectionectionection; @Autowired Private AuthenticationManager AuthenticationManager; @autowired private IntegrationUserDetailsService IntegrationUserDetailsService; @AutowiredプライベートWebresponseExceptionTranslator webresponseExceptionTranslator; @autowired private IntegrationAuthenticationFilter integrationAuthenticationFilter; @autowired private databasabasableclientdetailsservice redisclientDetailsService; @Override public void configure(clientDetailsserviceConfigurer client)スロー例外{// todo westingクライアントの詳細クライアント。 } @Override public void configure(authorationserverendpointsconfigurer endpoints){endpoints .tokenstore(new redistokenstore(redisconnectionFactory))// .AccessTokenconverter(jwtaccesstokencenverter().authenticationmanager(認証マネージャー).exceptionmanager(weauthmanager) .reuserefreshtokens(false).userdetailsService(IntegrationUserDetailsService); } @Override public void configure(authorizationserversecurityconfigurer security)スロー{security.allowformauthenticationforclients().tokenkeyaccess( "isauthenticated()").checktokenaccess( "pimitall()").addtokenEndpointAuthicationfilter(IntegrationAuthenticationFilter); } @bean publice passwordencoder passwordencoder(){return new bcryptpasswordencoder(); } @bean public jwtacstokenconverter jwtaccesstokenconverter(){jwtaccesstokenconverter jwtaccestokenconverter = new JWTACCESSTOKENVERTER(); JWTACCESSTOKENCONVERTER.SESTINGINGKEY( "Cola-Cloud"); jwtaccesstokenconverterを返します。 }}セキュリティを呼び出すことにより、インターセプターを認証チェーンに入れます。 .AddTokenEndPointAuthenticationFilter(IntegrationAuthenticationFilter);方法。
ステップ3:認証タイプに従ってユーザー情報を処理する
@ServicePublic Class IntegrationUserDetailsServiceは、userdetailsservice {@autowired private upmclient upmclient;プライベートリスト<IntegrationAuthenticator> Authenticators; @autowired(必須= false)public void setintegrationAuthenticators(list <統合Authenticator> Authenticators){this.authenticators = authenticators; } @Override public user loaduserbyUsername(string username)throws usernamenotfoundexception {IntegrationAuthentication IntegrationAuthentication = IntegrationAuthenticationContext.get(); //統合ログインであるかどうかを判断します(IntegrationAuthentication == null){IntegrationAuthentication = new IntegrationAuthentication(); } IntegrationAuthentication.setUsername(username); uservo uservo = this.authenticate(IntegrationAuthentication); if(uservo == null){新しいusernamenotfoundexception( "username or password error"); } user user = new user(); beanutils.copyproperties(uservo、user); this.setauthorize(user);ユーザーを返します。 } / ** *承認情報の設定 * * @param user * / public void setauthorize(user user){authorize authorize = this.upmclient.getauthorize(user.getid()); user.setroles(authorize.getroles()); user.setResources(authorize.getResources()); } private uservo Authenticate(IntegrationAuthentication IntegrationAuthentication){if(this.authenticators!= null){for(IntegrationAuthenticator Authenticator:Authenticators){if(Autherencator.Support(IntegrationAuthentication)){return autheristicator.Authenticate(IntegrationAuthentication); }} nullを返します。 }}これはintegrationUserdetailsServiceです。 Authenticateメソッドは、roaduserbyUsernameメソッドで呼び出されます。 Authenticateメソッドでは、現在のコンテキスト認証タイプは、異なるIntegrationAuthenticatorを呼び出してユーザー情報を取得します。デフォルトのユーザー名とパスワードの処理方法を見てみましょう。
@component @primarypublic class usernamepasswordauthenticator extends abstract preparable integrationauthenticator {@autowired private ucclient ucclient; @Override public uservo Authentication(IntegrationAuthentication IntegrationAuthentication){return ucclient.finduserbyUsername(integrationauthentication.getusername()); } @Override public void prepare(IntegrationAuthentication IntegrationAuthentication){} @OverRide public Boolean Support(IntegrationAuthentication IntegrationAuthentication){return stringutils.isempty(IntegrationAuthentication.getAuthType()); }}usernamepasswordauthenticatorは、指定された認証タイプなしでのみデフォルトの認証タイプを処理します。このクラスは、主にユーザー名を介してパスワードを取得します。次に、画像検証コードのログインを処理する方法を見てみましょう。
/***統合検証コード認証* @author liqiu* @date 2018-3-31 **/ @componentPublic Class CodeCodeCodeIntegrationAuthenticatorは、usernamepasswordauthenticatorを拡張します。 @autowired private vccclient vccclient; @Override public void prepare(IntegrationAuthentication IntegrationAuthentication){string vctoken = IntegrationAuthentication.getAuthParameter( "vc_token"); string vccode = IntegrationAuthentication.getAuthParameter( "vc_code"); //検証検証coderesult <boolean> result = vccclient.validate(vctoken、vccode、null); if(!result.getData()){throw new oauth2exception( "検証コードエラー"); }} @Override public boolean support(IntegrationAuthentication IntegrationAuthentication){return vidification_code_auth_type.equals(IntegrationAuthentication.getAuthType()); }}検証CodeIntegrationAuthenticatorは、usernamepasswordauthenticatorを継承します。これは、検証コードがprepereメソッドで正しいかどうか、ユーザーがユーザー名とパスワードを使用して取得したかどうかを確認する必要があるためです。ただし、認証タイプは処理する前に「VC」です。 SMS検証コードのログインがどのように処理されるかを見てみましょう。
@componentPublic class SMSINTERATIONAUTHENTICATOR EXTENTS ABSTROCT PREPARABLEABLE AUTHENTICATOR EXPREMENTS ApplicationEventPublisherAware {@autowired private ucclient ucclient; @autowired private vccclient vccclient; @AutowiredプライベートPasswordEncoder PasswordEncoder;プライベートApplicationEventPublisher ApplicationEventPublisher;プライベート最終静的文字列sms_auth_type = "sms"; @Override public uservo Authentication(IntegrationAuthentication IntegrationAuthentication){//パスワードを取得すると、実際の値は確認コード文字列パスワード= IntegrationAuthentication.getAuthParameter( "Password"); // usernameを取得すると、実際の値は携帯電話番号文字列ユーザー名= IntegrationAuthentication.getUsername()です。 //イベントを公開すると、ユーザーを自動的に登録するためにイベントを聴くことができます。ApplicationEventPublisher.publishevent(new smsauthenticatebeforevent(IntegrationAuthentication)); //携帯電話番号を介してユーザーをクエリしますuservo uservo = this.ucclient.finduserbyphoneNumber(username); if(uservo!= null){//パスワードを確認コードuservo.setpassword(passhipencoder.encode(password));として設定します。 //イベントを公開すると、メッセージ通知のためにイベントを聴くことができます。ApplicationEveventPublisher.publishevent(new smsauthenticateccessevent(IntegrationAuthentication)); } uservoを返します。 } @Override public void prepare(IntegrationAuthentication IntegrationAuthentication){string smstoken = IntegrationAuthentication.getAuthParameter( "SMS_TOKEN"); string smscode = IntegrationAuthentication.getAuthParameter( "Password"); string username = IntegrationAuthentication.getAuthParameter( "username"); result <boolean> result = vccclient.validate(smstoken、smscode、username); if(!result.getData()){new oauth2exception( "検証コードエラーまたはexpired"); }} @Override public boolean support(IntegrationAuthentication IntegrationAuthentication){return sms_auth_type.equals(IntegrationAuthentication.getAuthType()); } @Override public void setApplicationEventPublisher(ApplicationEventPublisher ApplicationEventPublisher){this.ApplicationEventPublisher = applicationEventPublisher; }}SMSintegrationAuthenticatorは、ログインしたSMS検証コードを事前に処理して、違法かどうかを判断します。違法である場合、ログインを直接中断します。プリプロセシングが渡された場合、ユーザー情報を取得するときに携帯電話番号を介してユーザー情報が取得され、パスワードがリセットされ、後続のパスワード検証が渡されます。
要約します
このソリューションでは、統合されたログインの問題を解決するための責任チェーンおよびアダプター設計パターンの主な使用により、スケーラビリティが向上し、Springのソースコードが汚染されません。他のログインを継承したい場合は、カスタムIntegrationAuthenticatorを実装するだけです。
プロジェクトアドレス:https://gitee.com/leecho/cola-cloud
ローカルダウンロード:Cola-Cloud_jb51.rar
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。