Vorwort
Bei der Verwendung von SpringCloud zum Bau eines verteilten Systems mit Microservice -Architektur ist OAuth2.0 der Branchenstandard für die Zertifizierung. Die Spring Security OAuth2 bietet außerdem eine vollständige Reihe von Lösungen, um die Verwendung von OAuth2.0 in der Spring Cloud/Spring-Boot-Umgebung zu unterstützen, wobei außerhalb des Box-Komponenten bereitgestellt werden. Während des Entwicklungsprozesses werden wir jedoch feststellen, dass die Komponenten der Frühlingssicherheit OAuth2 besonders umfassend sind, die es sehr unpraktisch macht, die Erweiterungslösung direkt anzugeben, wie z.
Wenn sich dieser Szenarien gegenübersteht, wird erwartet, dass viele Menschen, die mit Frühlingssicherheit nicht vertraut sind, nicht in der Lage sein, zu beginnen. Wie man basierend auf den oben genannten Szenario-Anforderungen in die elegante Integration von SMS-Verifizierungscode-Anmeldung und Login von Drittanbietern und wie sie als elegant integriert angesehen wird? Es gibt die folgenden Anforderungen:
Basierend auf den oben genannten Entwurfsanforderungen werden wir detailliert einführen, wie eine Reihe von integrierten Anmeldeauthentifizierungskomponenten entwickelt werden, um die oben genannten Anforderungen im Artikel zu erfüllen.
Lesen Sie diesen Artikel, den Sie über OAuth2.0 -Zertifizierungssystem, Springboot, Spring Security, Spring Cloud und andere verwandte Kenntnisse informieren müssen
Ideen
Schauen wir uns den Authentifizierungsprozess von Frühlingssicherheit an: OAuth2:
In diesem Prozess gibt es nicht viele Einstiegspunkte, und die Idee des integrierten Anmeldes lautet wie folgt:
Nach dem Zugriff auf diesen Prozess können Sie im Grunde genommen elegant Drittanmeldungen integrieren.
erreichen
Nach der Einführung der Ideen zeigt der folgende Code, wie sie implementiert werden sollen:
Der erste Schritt besteht darin, den Interceptor für Abfang -Anmeldeanforderungen zu definieren
/** * @Author liqiu * @date 2018-3-30 **/ @componentPublic class IntegrationAuthenticationFilter erweitert GenericFilterbean ApplicationContextaware {private statische endgültige String auth_type_parm_name = "author_type"; private statische endgültige Zeichenfolge oAuth_Token_url = "/oAuth/token"; private Sammlung <IntegrationAuthenticator> Authentikatoren; private applicationContext applicationContext; private requestMatcher requestMatcher; public integrationAuthenticationFilter () {this.requestMatcher = new orRequestMatcher (neuer AntpathequestMatcher (OAuth_Token_url, "get"), neuer AntpathequestMatcher (OAuth_Token_url, "post"); } @Override public void dofilter (servletRequest servletRequest, ServletResponse ServletResponse, Filterchain FilterChain) löscht IoException, ServletException {httpServletRequest Request = (httpServletRequest) servletRequest; HttpServletResponse response = (httpServletResponse) servletResponse; if (requestMatcher.matches (request)) {// Integrierte Anmeldeinformation IntegrationAuthentication IntegrationAuthentication = new IntegrationAuthentication (); IntegrationAuthentication.setAuthType (request.getParameter (auth_type_parm_name)); IntegrationAuthentication.SetAuthParameters (Request.GetParameterMap ()); IntegrationAuthenticationContext.set (IntegrationAuthentication); Versuchen Sie {// Vorverarbeitung this.Prepare (IntegrationAuthentication); filterchain.dofilter (Anfrage, Antwort); // Nachbearbeitung von this.crate (IntegrationAuthentication); } endlich {integrationAuthenticationContext.clear (); }} else {filterchain.dofilter (request, Antwort); }} / *** Vorverarbeitung* @param IntegrationAuthentication* / private void prepe (IntegrationAuthentication IntegrationAuthentication) {// Lazy Loading Authenticator if (this.authenticators == null) {synchronisierte (this) {map <String, IntegrationAuthenticator> IntegrationAuthenticatorMaTora = Away, Map <String, IntegrationAuthenticator> IntegrationAuthenticaTicatorMca. applicationContext.getBeansOftype (IntegrationAuthenticator.Class); if (integrationAuthenticatormap! = null) {this.authenticators = IntegrationAuthenticatOrMap.Values (); }}} if (this.authenticators == null) {this.authenticators = new ArrayList <> (); } für (IntegrationAuthenticator Authenticator: Authenticators) {if (authenticator.support (IntegrationAuthentication)) {authenticator.prepare (IntegrationAuthentication); }}} / *** Post-Prozessing* @param integrationAuthentication* / private void complete (IntegrationAuthentication IntegrationAuthentication) {für (IntegrationAuthenticator Authentifizierung: Authentifizierung) {if (Authenticator.Support (IntegrationAuthentication) {Authentifizierung.Cration.complete.complete (Authenticator); }}} @Override public void setApplicationContext (ApplicationContext applicationContext) löst beansexception {this.applicationContext = ApplicationContext aus; }}In dieser Klasse sind zwei Teile der Arbeiten hauptsächlich abgeschlossen: 1. Erhalten Sie den aktuellen Authentifizierungstyp gemäß den Parametern, 2. Rufen Sie den verschiedenen IntegrationAuthenticator auf.
Schritt 2: Stecken Sie den Interceptor in die Abfangkette
/** * @Author liqiu * @date 2018-3-7 **/ @configuration @EnableAuthorizationServerPublic Class AutorizationServerConfiguration erweitert AutorisierungenserverConFigurerAdapter {@autowired Private RedisconNectory RedisconnectionFactory; @Autowired Private AuthenticationManager AuthenticationManager; @Autowired Private IntegrationUserDetailsService IntegrationUserDetailsService; @Autowired Private WebePonsexceptionTranslator WebePonsexceptionTranslator; @Autowired Private IntegrationAuthenticationFilter IntegrationAuthenticationFilter; @Autowired Private DatabaseCAchableClientDetailsService RedisclientDetailsService; @Override public void configure (ClientDetailsServiceConFigurer Clients) löst eine Ausnahme aus {// todo persist Clients Details Clients.WithClientDetails (RedisclientDetailsService); } @Override public void configure (AutorisierungserverendpointsconFigurer -Endpunkte) {Endpoints .TokenStore (neuer redistokenStore (redisconnectionFactory) // .AccessTokenConverter (jwtaccessTokenConverter () .AuthenticationManAnman). .ReusereReFreshtokens (Falsch) .userDetailsService (IntegrationUSerDetailsService); } @Override public void configure (autorisierungsversucheConfigurer -Sicherheit) löst Ausnahme aus {Security.AllowFormAuthenticationForClients () .TokenKeyAccess ("isauthenticated ()") .CheckTokenAccess ("erlaubteAll () .AddtokenAthenticumingFilter (IntegrationAuthentictionfilter); } @Bean public passwordEnCoder passwordEnCoder () {Neue bcryptPasswordEnCoder () zurückgeben; } @Bean public JwtaccessTokenConverter jwtaccessToKenConverter () {jwtaccessTokenConverter jwtaccessTokenConverter = new JwtaccessTokenConverter (); JwtaccessTokenConverter.SetsigningKey ("Cola-cloud"); return jwtaccessTokenConverter; }}Setzen Sie den Interceptor in die Authentifizierungskette, indem Sie die Sicherheit aufrufen. .AddTokenDointAuthenticationFilter (IntegrationAuthenticationFilter); Verfahren.
Schritt 3: Verarbeiten Sie Benutzerinformationen entsprechend dem Authentifizierungstyp
@ServicePublic Class IntegrationUSerDetailsService implementiert UserDetailsService {@autowired private upmclient upmclient; private Liste <IntegrationAuthenticator> Authentikatoren; @Autowired (erforderlich = Falsch) public void setInteInauthenticators (Liste <IntegrationAuthenticator> Authenticators) {this.authenticators = Authenticators; } @Override public User LoadUserByUserName (String -Benutzername) löst ustamenotFoundException {IntegrationAuthentication IntegrationAuthentication = IntegrationAuthenticationContext.get () aus; // beurteilen, ob es sich um eine integrierte Anmeldung if (IntegrationAuthentication == null) {IntegrationAuthentication = new IntegrationAuthentication (); } IntegrationAuthentication.Setusername (Benutzername); Uservo uservo = this.Authenticate (IntegrationAuthentication); if (uservo == null) {neue usernamenotfoundException ("Benutzername oder Kennwortfehler"); } User user = new user (); Beanutils.CopyProperties (Uservo, Benutzer); this.setAuthorize (Benutzer); Benutzer zurückgeben; } / ** * Autorisierungsinformationen festlegen * * @param user * / public void setAuthorize (Benutzer Benutzer) {autorize autorize = this.upmclient.getAuthorize (user.getId ()); user.setroles (autorize.getroles ()); user.setResources (autorize.getResources ()); } private UserVO -Authentikat (IntegrationAuthentication IntegrationAuthentication) {if (this.authenticators! }} return null; }}Hier ist ein IntegrationSerDetailsService. Die authentifizierende Methode wird in der LOADUSERBYUSERNAME -Methode aufgerufen. In der authentifizierenden Methode ruft der aktuelle Kontext -Authentifizierungstyp unterschiedlicher IntegrationAuthenticator auf, um Benutzerinformationen zu erhalten. Schauen wir uns an, wie der Standard -Benutzername und das Standardkennwort behandelt werden:
@Component @PrimaryPublic Class usernamePasswordAuthenticator erweitert abstraktParable integrationAuthenticator {@autowired private Ucclient ucclient; @Override public uservo Authentifizierung (IntegrationAuthentication IntegrationAuthentication) {return ucclient.finduserByusername (IntegrationAuthentication.getUnername ()); } @Override public void prepe (IntegrationAuthentication IntegrationAuthentication) {} @Override public boolean Support (IntegrationAuthentication IntegrationAuthentication) {return Stringutils.isempty (IntegrationAuthentication.getAuthtype ()); }}UsernamepasswordAuthenticator verarbeitet den Standardauthentifizierungstyp nur ohne angegebene Authentifizierungstyp. Diese Klasse erhält hauptsächlich Passwörter über den Benutzernamen. Schauen wir uns anschließend an, wie Sie die Anmeldung des Image -Überprüfungscodes umgehen:
/*** Integrierter Verifizierungscode-Authentifizierung* @Author liqiu* @date 2018-3-31 **/ @componentpublic class VerificationCodeInegationAuthenticator erweitert userernAmepasswordAuthenticator {private endgültige statische String-Verifizierung_Code_AUTH_TYTYTYNE = "VC"; @Autowired Private Vccclient VccClient; @Override public void prepe (IntegrationAuthentication IntegrationAuthentication) {String vctoken = IntegrationAuthentication.getAuthParameter ("vc_token"); String vccode = integrationAuthentication.getAuthParameter ("vc_code"); // Überprüfung der Verifizierung coderesult <boolean> result = vccclient.validat (vctoken, vccode, null); if (! result.getData ()) {neue oAuth2Exception ("Verifizierungscode -Fehler"); }} @Override public boolean Support (IntegrationAuthentication IntegrationAuthentication) {return verification_code_auth_type.equals (integrationAuthentication.getAuthtype ()); }}VerificationCodeInteGrationAuthenticator erbt den usernamepasswordAuthenticator, da er nur überprüfen muss, ob der Verifizierungscode in der Methode vorbereitet ist und ob der Benutzer ihn unter Verwendung des Benutzernamens und des Kennworts erhalten hat. Der Authentifizierungstyp ist jedoch "VC", bevor er verarbeitet werden kann. Schauen wir uns an, wie der SMS -Verifizierungscode -Login behandelt wird:
@ComponentPublic Class SMSIneInegationAuthenticator erweitert abstractParable IntegrationAuthenticator implementiert ApplicationEventPublisheraware {@autowired Private Ucclient ucclient; @Autowired Private Vccclient VccClient; @Autowired Private PasswordEnCoder PasswordEncoder; private ApplicationEventPublisher ApplicationEventPublisher; private endgültige statische String sms_auth_type = "sms"; @Override public uservo Authentifizierung (IntegrationAuthentication IntegrationAuthentication) {// Kennwort abrufen, der tatsächliche Wert ist das Verifizierungscode -String -Passwort = IntegrationAuthentication.getAuthParameter ("Passwort"); // Benutzername abrufen, der tatsächliche Wert ist der Mobiltelefonnummer String username = integrationAuthentication.getUername (); // Ereignisse veröffentlichen, können Sie Ereignisse anhören, um den Benutzer automatisch zu registrieren. // Benutzer über die Mobiltelefonnummer uservo uservo = this.ucclient.finduserByphonNumber (Benutzername) abfragen; if (uservo! // Ereignisse veröffentlichen, können Sie Ereignisse zur Nachrichtenbenachrichtigung anhören. } return uservo; } @Override public void prepe (IntegrationAuthentication IntegrationAuthentication) {String smstoken = integrationAuthentication.getAuthParameter ("sms_token"); String SMSCODE = IntegrationAuthentication.getAuthParameter ("Passwort"); String username = IntegrationAuthentication.getAuthParameter ("Benutzername"); Result <boolean> result = vccclient.validate (SMStoken, Smscode, Benutzername); if (! result.getData ()) {neue oAuth2Exception ("Verifizierungscode -Fehler oder abgelaufen"); }} @Override public boolean Support (IntegrationAuthentication IntegrationAuthentication) {return sms_auth_type.equals (IntegrationAuthentication.getAuthtype ()); } @Override public void setApplicationEventPublisher (ApplicationEventPublisher ApplicationEventPublisher) {this.applicationEventPublisher = ApplicationEventPublisher; }}SMSINTEGRATIONAUTUTHENTICATOR wird den angemeldeten SMS-Verifizierungscode vorbereiten, um festzustellen, ob er illegal ist. Wenn es illegal ist, unterbricht es das Anmeldung direkt. Wenn die Vorverarbeitung übergeben wird, werden die Benutzerinformationen über die Mobiltelefonnummer erhalten, wenn die Benutzerinformationen abgerufen werden, und das Kennwort wird zurückgesetzt, um die nachfolgende Passwortüberprüfung zu übergeben.
Zusammenfassen
In dieser Lösung wird die Hauptverantwortung der Verantwortungskette und des Adapter -Designmusters zur Lösung des Problems der integrierten Anmeldung verbessert, die Skalierbarkeit und den Quellcode des Frühlings nicht verschmutzt. Wenn Sie andere Anmeldungen erben möchten, müssen Sie nur einen benutzerdefinierten IntegrationAuthenticator implementieren.
Projektadresse: https://gitee.com/leecho/cola-cloud
Lokaler Download: Cola-cloud_jb51.rar
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.