머리말
SpringCloud를 사용하여 마이크로 서비스 아키텍처를 사용하여 분산 시스템을 구축 할 때 OAUTH2.0은 인증을위한 업계 표준입니다. Spring Security OAUTH2는 또한 Spring Cloud/Spring Boot 환경에서 OAUTH2.0 사용을 지원하기위한 완전한 솔루션 세트를 제공하여 기본 구성 요소를 제공합니다. 그러나 개발 프로세스 중에 Spring Security OAUTH2의 구성 요소가 특히 포괄적이므로 확장하기가 매우 불편하거나 다음과 같은 확장 솔루션을 직접 지정하는 것이 쉽지 않다는 것을 알 수 있습니다.
이러한 시나리오에 직면 할 때 스프링 보안에 익숙하지 않은 많은 사람들이 시작할 수 없을 것으로 예상됩니다. 위의 시나리오 요구 사항을 기반으로 SMS 검증 코드 로그인 및 타사 로그인을 우아하게 통합하는 방법 및 우아하게 통합되는 방법은 무엇입니까? 다음 요구 사항이 있습니다.
위의 설계 요구 사항을 기반으로, 우리는 기사의 위 요구 사항을 충족시키기 위해 통합 로그인 인증 구성 요소 세트를 개발하는 방법을 자세히 소개합니다.
이 기사를 읽으십시오. OAUTH2.0 인증 시스템, SpringBoot, Springsecurity, Spring Cloud 및 기타 관련 지식에 대해 알아야합니다.
아이디어
Spring Security Oauth2의 인증 프로세스를 살펴 보겠습니다.
이 과정에서는 진입 점이 많지 않으며 통합 로그인에 대한 아이디어는 다음과 같습니다.
이 프로세스에 액세스 한 후 기본적으로 타사 로그인을 우아하게 통합 할 수 있습니다.
성취하다
아이디어를 소개 한 후 다음 코드는이를 구현하는 방법을 보여줍니다.
첫 번째 단계는 인터셉터를 인터셉트 로그인 요청을 정의하는 것입니다.
/** * @author liqiu * @Date 2018-3-30 **/ @componentPublic 클래스 통합 AuthenticationFilter는 GenericFilterBean ApplicationContextAware {private static final string auth_type_pepe_name = "auth_type"; 개인 정적 최종 문자열 OAuth_Token_url = "/oauth/token"; 개인 컬렉션 <IntegrationAuthenticator> 인증 자; Private ApplicationContext ApplicationContext; 개인 요청 관리자 요청 관리자; Public IntegrationAuthenticationFilter () {this.requestMatcher = New OrrequestMatcher (New AntpathRequestMatcher (OAUTH_TOKEN_URL, "GET"), New AntpathRequestMatcher (OAUTH_TOKEN_URL, "POST"); } @override public void dofilter (servletrequest servletrequest, servletreponse servletresponse, filterchain filterchain)는 ioexception, servletexception {httpservletrequest request = (httpservletrequest) servletrequest; httpservletresponse 응답 = (httpservletResponse) servletResponse; if (requestmatcher.matches (request)) {// 통합 로그인 정보 통합 통합 통합 integrationalication = new IntegrationAuthentication (); IntegrationAuthentication.setAuthType (request.getParameter (auth_type_parm_name)); IntegrationAuthentication.setauthparameters (request.getParameterMap ()); IntegrationAuthenticationContext.set (IntegrationAuthentication); {// preprocessing this.prepare (integrationauthentication); filterchain.dofilter (요청, 응답); // post-processing this.complete (Integrationauthentication); } 마침내 {integrationAuthenticationContext.clear (); }} else {filterchain.dofilter (요청, 응답); }} / *** 전처리* @Param IntegrationAuthentication* / private void 준비 (IntegrationAuthentication IntegrationAuthentication) {// 게으른로드 인증기 if (this.authenticators == null) {this) {map <문자열, IntegrationAuthenticator> integrationAuthationAtormap = 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); }}} / *** 사후 처리* @Param IntegrationAuthentication* / private void complete (IntegrationAuthentication IntegrationAuthentication) {for (integrationAuthenticator Authentication : Authentications) {if (authenticator.support (IntegrationAuthentication)) {authentication.complete (integrationAuthentication); }}} @override public void setApplicationContext (ApplicationContext ApplicationContext)는 beansexception {this.applicationContext = ApplicationContext; }}이 클래스에서 작업의 두 부분이 주로 완료됩니다. 1. 매개 변수에 따라 현재 인증 유형을 얻으십시오.
2 단계 : 인터셉터를 인터셉트 체인에 넣습니다
/** * @author liqiu * @date 2018-3-7 **/ @configuration @enableAuthorizationSerPublic Class AutherizationSeRizeRizeRverVerConfiguration interizationSationSeRverConfigerRadapter {@autowired private readisconceCnection factory readisconnection factory; @autowired Private AuthenticationManager AuthenticationManager; @autowired Private IntegrationUserDetailsService IntegrationUserDetailsService; @autowired Private WebresponseExceptionTranslator WebresponseExceptionTranslator; @autowired Private IntegrationAuthenticationFilter IntegrationAuthenticationFilter; @autowired private databasecachableclientDetailsService redisclientDetailsService; @override public void configure (clientDetailsServiceConfigurer 클라이언트) 예외 {// todo pass clients clients.withClientDetails (redisclientDetailsService); } @override public void configure (AwrowizationServerendPointSconfiger endPoints) {endPoints .TokenStore (new redistokenStore (readisconnectionFactory)) // .AccessTokenConverter (jwtacesstokenConverter ()). .ExceptionTranslator (WebresponseExceptionTranslator) .reusereReshTokens (false) .UserDetailsService (IntegrationUserDetailsService); } @override public void configure (AwrowizationSeRverseCurityConfigurer Security)는 예외 {security.allowFormauthenticationForclients () .TokenKeyAccess ( "isauthenticated ()") .checktokencess ( "permitall ()".AddokenendPointAuthenticationFilter (integrationAuthenticfilter); } @bean public parbliceNcoder passwordEncoder () {return new bcryptpasswordencoder (); } @Bean public JWTACCESSTOKENCONVERTER JWTACCESSTOKENCONVERTER () {JWTACCESSTOKENCONVERTER JWTACCESSTOKENCONVERTER = NEW JWTACCESSTOKENCONVERTER (); jwtaccesstokenconverter.setsigningkey ( "cola-cloud"); jwtaccesstokenconverter를 반환합니다. }}보안을 호출하여 인터셉터를 인증 체인에 넣으십시오. .addtokenendpointauthenticationFilter (IntegrationAuthenticationFilter); 방법.
3 단계 : 인증 유형에 따라 사용자 정보를 처리합니다.
@ServicePublic Class IntegrationUserDetailsService 구현 userDetailsService {@autowired private upmclient upmclient; 비공개 목록 <Integrationauthenticator> 인증 자; @autowired (필수 = 거짓) public void setIntegrationAuthenticators (list <integrationauthenticator> authenticators) {this.authenticators = authenticators; } @override public user loadUserByUserName (String username)은 usernamenotfoundException {integrationAuthentication IntegrationAuthentication = integrationAuthenticationContext.get (); // IF (IntegrationAuthentication == null) {integrationAuthentication = new IntegrationAuthentication (); } integrationAuthentication.setUserName (사용자 이름); uservo uservo = this.authenticate (Integrationauthentication); if (uservo == null) {새 usernamenotfoundException ( "사용자 이름 또는 비밀번호 오류"); } user user = new user (); beanutils.copyproperties (uservo, user); this.setAuthorize (user); 리턴 사용자; } / ** * 권한 부여 정보 설정 * * @param user * / public void setAuthorize (user user) {authorize the eporderize = this.upmclient.getAuthorize (user.getId ()); user.setroles (authorize.getRoles ()); user.setResources (authorize.getResources ()); } private uservo 인증 (IntegrationAuthentication IntegrationAuthentication) {if (this.authenticators! = null) {for (integrationAuthenticator authenticator : authenticators) {if (authenticator.support (IntegrationAuthentication)) {return Authenticator.authentication (IntegrationAuthentication); }} return null; }}다음은 IntegrationUserDetailsService입니다. 인증 메소드는 loadUserByUserName 메소드에서 호출됩니다. 인증 메소드에서 현재 컨텍스트 인증 유형은 다른 IntegrationAuthenticator를 호출하여 사용자 정보를 얻습니다. 기본 사용자 이름과 비밀번호가 어떻게 처리되는지 살펴 보겠습니다.
@component @primarypublic class usernamepasswordauthenticator acpractPreparableIntegrationAuthenticator {@autowired private ucclient ucclient; @override public uservo 인증 (IntegrationAuthentication IntegrationAuthentication) {return ucclient.finduserByUserName (integrationAuthentication.getUserName ()); } @Override public void repay (IntegrationAuthentication IntegrationAuthentication) {} @override public boolean support (IntegrationAuthentication IntegrationAuthentication) {return stringUtils.isempty (integrationAuthentication.getAuthType ()); }}usernamepasswordauthenticator는 지정된 인증 유형없이 기본 인증 유형 만 처리합니다. 이 클래스는 주로 사용자 이름을 통해 암호를 얻습니다. 다음으로 이미지 확인 코드 로그인을 처리하는 방법을 살펴 보겠습니다.
/*** 통합 검증 코드 인증* @Author liqiu* @Date 2018-3-31 **/ @componentPublic 클래스 verificationCodeIntegrationAuthenticator usernamepasswordauthenticator {private final static string verification_code_auth_type = "vc"; @autowired private vccclient vccclient; @override public void repay (IntegrationAuthentication IntegrationAuthentication) {String vctoken = integrationAuthentication.getAuthParameter ( "vc_token"); 문자열 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 verification_code_auth_type.equals (integrationAuthentication.getAuthType ()); }}VerificationCodeIntegrationAuthenticator는 usernamepasswordauthenticator를 상속합니다. 확인 방법에서 확인 코드가 올바른지 여부와 사용자가 사용자 이름과 비밀번호를 사용하여이를 얻었는지 여부를 확인하면됩니다. 그러나 인증 유형은 처리되기 전에 "VC"입니다. SMS 검증 코드 로그인이 어떻게 처리되는지 살펴 보겠습니다.
@componentpublic class smsintegrationauthenticator 확장 acplicateventeGrationAuthenticator는 ApplicationEventPublisherAware {@autowired private ucclient ucclient; @autowired private vccclient vccclient; @autowired private passwordencoder passwordencoder; Private ApplicationEventPublisher ApplicationEventPublisher; 개인 최종 정적 문자열 sms_auth_type = "sms"; @override public uservo Authentication (IntegrationAuthentication IntegrationAuthentication) {// 비밀번호 가져 오기, 실제 값은 검증 코드 문자열 암호 = integrationAuthentication.getAuthParameter ( "password"); // 사용자 이름을 얻습니다. 실제 값은 휴대 전화 번호 문자열 username = integrationAuthentication.getUnerame (); // 이벤트를 게시하면 이벤트를 듣고 사용자를 자동으로 등록 할 수 있습니다. // 휴대 전화 번호를 통한 사용자 쿼리 사용자 uservo uservo = this.ucclient.finduserByphonEnumber (사용자 이름); if (uservo! = null) {// 암호를 확인 코드로 설정합니다. // 이벤트 게시, 메시지 알림에 대한 이벤트를들을 수 있습니다. } return uservo; } @override public void repay (IntegrationAuthentication IntegrationAuthentication) {String smstoken = integrationAuthentication.getAuthParameter ( "sms_token"); 문자열 smscode = integrationAuthentication.getAuthParameter ( "password"); 문자열 username = integrationAuthentication.getAuthParameter ( "사용자 이름"); 결과 <boolean> result = vccclient.validate (smstoken, smscode, username); if (! result.getData ()) {Throw New Oauth2Exception ( "검증 코드 오류 또는 만료"); }} @override public boolean support (IntegrationAuthentication IntegrationAuthentication) {return sms_auth_type.equals (IntegrationAuthentication.getAuthType ()); } @override public void setApplicationEventPublisher (ApplicationEventPublisher ApplicationEventPublisher) {this.applicationEventPublisher = ApplicationEventPublisher; }}smsintegrationauthenticator는 로그인 된 SMS 검증 코드를 사전 처리하여 불법인지 여부를 결정합니다. 불법 인 경우 로그인을 직접 방해합니다. 전처리가 전달되면 사용자 정보를 얻을 때 휴대폰 번호를 통해 사용자 정보를 얻게되며 암호가 후속 비밀번호 확인을 통과하도록 재설정됩니다.
요약
이 솔루션에서는 통합 로그인 문제를 해결하기 위해 책임 체인 및 어댑터 설계 패턴의 주요 사용으로 확장 성을 향상 시키며 스프링 소스 코드를 오염시키지 않습니다. 다른 로그인을 상속 받으려면 사용자 정의 IntegrationAuthenticator 만 구현하면됩니다.
프로젝트 주소 : https://gitee.com/leecho/colacloud
로컬 다운로드 : cola-cloud_jb51.rar
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.