คำนำ
เมื่อใช้ SpringCloud เพื่อสร้างระบบแบบกระจายด้วยสถาปัตยกรรม Microservice OAuth2.0 เป็นมาตรฐานอุตสาหกรรมสำหรับการรับรอง Spring Security OAUTH2 ยังมีชุดโซลูชั่นที่สมบูรณ์เพื่อรองรับการใช้ OAuth2.0 ในสภาพแวดล้อมการบูตคลาวด์/สปริงสปริง อย่างไรก็ตามในระหว่างกระบวนการพัฒนาเราจะพบว่าเนื่องจากส่วนประกอบของ Spring Security OAUTH2 นั้นครอบคลุมเป็นพิเศษสิ่งนี้ทำให้ไม่สะดวกมากที่จะขยายหรือไม่ง่ายที่จะระบุโซลูชันส่วนขยายโดยตรงเช่น:
เมื่อเผชิญกับสถานการณ์เหล่านี้คาดว่าคนจำนวนมากที่ไม่คุ้นเคยกับ Spring Security OAuth2 จะไม่สามารถเริ่มต้นได้ ขึ้นอยู่กับข้อกำหนดของสถานการณ์ข้างต้นวิธีการรวมการเข้าสู่ระบบการตรวจสอบ SMS และการเข้าสู่ระบบของบุคคลที่สามอย่างหรูหราและวิธีการพิจารณาแบบบูรณาการอย่างสง่างาม มีข้อกำหนดดังต่อไปนี้:
ตามข้อกำหนดการออกแบบข้างต้นเราจะแนะนำรายละเอียดเกี่ยวกับวิธีการพัฒนาชุดของส่วนประกอบการตรวจสอบล็อกอินแบบบูรณาการเพื่อตอบสนองความต้องการข้างต้นในบทความ
อ่านบทความนี้คุณต้องรู้เกี่ยวกับระบบการรับรอง OAuth2.0, Springboot, Springsecurity, Spring Cloud และความรู้อื่น ๆ ที่เกี่ยวข้อง
ความคิด
มาดูกระบวนการตรวจสอบความปลอดภัยของ Spring Security OAuth2:
ในกระบวนการนี้มีจุดเข้าไม่มากนักและแนวคิดของการเข้าสู่ระบบแบบบูรณาการมีดังนี้:
หลังจากเข้าถึงกระบวนการนี้คุณสามารถรวมเข้าสู่ระบบของบุคคลที่สามอย่างสง่างาม
ทำให้สำเร็จ
หลังจากแนะนำแนวคิดรหัสต่อไปนี้จะแสดงวิธีการใช้งาน:
ขั้นตอนแรกคือการกำหนดตัวดักจับเพื่อสกัดกั้นการร้องขอการเข้าสู่ระบบ
/** * @author liqiu * @date 2018-3-30 **/ @ComponentPublic คลาส IntegrationAuthenticationFilter ขยาย GenericFilterBean ใช้ ApplicationContextAware {สตริงสุดท้ายคงที่ auth_type_parm_name = "auth_type"; สตริงสุดท้ายคงที่ส่วนตัว OAuth_token_url = "/oauth/token"; คอลเลกชันส่วนตัว <IntegrationAuthenticator> Authenticators; ApplicationContext Private ApplicationContext; ผู้ร้องขอส่วนตัว requestmatcher; Public IntegrationAuthenticationFilter () {this.requestMatcher = ใหม่ orrequestmatcher (ใหม่ antpathrequestmatcher (OAuth_token_url, "Get"), ใหม่ AntpathRequestMatcher (OAuth_Token_url, "Post")); } @Override โมฆะสาธารณะ Dofilter (ServletRequest ServletRequest, ServletResponse ServletResponse, FilterChain FilterChain) พ่น IOException, ServleTexception httpservletResponse response = (httpservletResponse) servletResponse; if (requestmatcher.matches (คำขอ)) {// ตั้งค่าข้อมูลการเข้าสู่ระบบแบบบูรณาการรวมการรวมการรวมกลุ่มการรวมตัว = ใหม่ IntegrationAuthentication (); IntegrationAuthentication.setAuthType (request.getParameter (auth_type_parm_name)); IntegrationAuthentication.setAuthParameters (request.getParameterMap ()); IntegrationAuthenticationContext.set (IntegrationAuthentication); ลอง {// preprocessing this.pare (integrationauthentication); FilterChain.dofilter (คำขอ, การตอบกลับ); // หลังการประมวลผล this.complete (Integrationauthentication); } ในที่สุด {IntegrationAuthenticationContext.clear (); }} else {filterchain.dofilter (คำขอ, การตอบกลับ); }} / *** การประมวลผลล่วงหน้า* @param IntegrationAuthentication* / โมฆะส่วนตัวเตรียม (IntegrationAuthentication Integrationauthentication) {// Lazy Loading Authenticator ถ้า (this.Authenticators == NULL) {ซิงโครไนซ์ ApplicationContext.getBeansOfType (IntegrationAuthenticator.class); if (IntegrationAuthenticatorMap! = null) {this.authenticators = integrationauthenticatormap.values (); }}} if (this.authenticators == null) {this.authenticators = new ArrayList <> (); } สำหรับ (IntegrationAuthenticator Authenticator: Authenticators) {ถ้า (Authenticator.support (IntegrationAuthentication)) {Authenticator.Prepare (IntegrationAuthentication); }}} / *** โพสต์การประมวลผล* @param integrationauthentication* / โมฆะส่วนตัวเสร็จสมบูรณ์ (การรวมการรวมกลุ่มการรวมตัวกัน) {สำหรับ (Integrationauthenticator Authentication: การรับรองความถูกต้อง) {ถ้า (Authenticator.support (Integrationauthentication) }}} @Override โมฆะสาธารณะ setApplicationContext (ApplicationContext ApplicationContext) พ่น beansexception {this.applicationContext = ApplicationContext; -ในชั้นเรียนนี้งานสองส่วนจะเสร็จสมบูรณ์เป็นหลัก: 1. รับประเภทการตรวจสอบความถูกต้องปัจจุบันตามพารามิเตอร์ 2. การเรียกใช้ integrationauthenticator ที่แตกต่างกัน
ขั้นตอนที่ 2: ใส่ interceptor ลงในห่วงโซ่การสกัดกั้น
/** * @author liqiu * @date 2018-3-7 **/ @การกำหนดค่า @enableauthorizationserverpublic การอนุญาตคลาส @autowired AuthenticationManager AuthenticationManager; @autowired IntegrationUserDetailsService IntegrationUserDetailsService; @autowired ส่วนตัว webresponseExceptionTranslator WebResponSeExceptionTranslator; @autowired IntegrationauthenticationFilter IntegrationAuthenticationFilter; @autoWired DatabaseCachableClientDetailsService redisclientDetailservice; @Override โมฆะสาธารณะการกำหนดค่า (ไคลเอนต์ไดเทอร์สเซอร์ซิคคอนเนคเตอร์ลูกค้า) โยนข้อยกเว้น {// todo ยังคงมีลูกค้ารายละเอียดลูกค้ารายละเอียดลูกค้า withClientDetails (redisclientDetailsService); } @Override โมฆะสาธารณะการกำหนดค่า (AuthorizationServerendPointSconFigurer จุดสิ้นสุด) {จุดสิ้นสุด. Tokenstore (ใหม่ redistokenstore (redisconnectionFactory)) // .accessTokenConverter .ReuserefreshTokens (เท็จ) .USERDETAILSSERVICE (IntegrationUserDetailsService); } @Override โมฆะสาธารณะการกำหนดค่า (AuthorizationServersecurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurityCurity } @Bean รหัสผ่านสาธารณะรหัสผ่านรหัสผ่าน () {ส่งคืน bcryptPasswordEncoder ใหม่ (); } @Bean สาธารณะ jwtaccessTokenconverter jwtaccessTokenconverter () {jwtaccessTokenconverter jwtaccessTokenConverter = new JWTaccessTokenConverter (); jwtaccessTokenconverter.setSigningKey ("Cola-Cloud"); return jwtaccesstokenconverter; -ใส่ interceptor ลงในห่วงโซ่การรับรองความถูกต้องโดยเรียกความปลอดภัย .AddokenendPointauthenticationFilter (IntegrationAuthenticationFilter); วิธี.
ขั้นตอนที่ 3: ประมวลผลข้อมูลผู้ใช้ตามประเภทการรับรองความถูกต้อง
@ServicePublic Class IntegrationUserDetailsService ดำเนินการ UserDetailsService {@AutoWired Private Upmclient Upmclient; รายการส่วนตัว <IntegrationAuthenticator> Authenticators; @autowired (จำเป็น = false) โมฆะสาธารณะ setIntegrationAuthenticators (รายการ <IntegrationAuthenticator> Authenticators) {this.Authenticators = Authenticators; } @Override ผู้ใช้สาธารณะ LoadUserByUserName (ชื่อผู้ใช้สตริง) พ่น USERNAMENOTFoundException {IntegrationAuthentication IntegrationAuthentication = IntegrationAuthenticationContext.get (); // ตัดสินว่าเป็นการเข้าสู่ระบบแบบบูรณาการหรือไม่หาก (IntegrationAuthentication == NULL) {IntegrationAuthentication = new IntegrationAuthentication (); } IntegrationAuthentication.setUserName (ชื่อผู้ใช้); uservo uservo = this.authenticate (Integrationauthentication); ถ้า (uservo == null) {โยน usernamenotfoundException ใหม่ ("ชื่อผู้ใช้หรือรหัสผ่านข้อผิดพลาด"); } ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); beanutils.copyproperties (Uservo, ผู้ใช้); this.setauthorize (ผู้ใช้); ผู้ใช้ส่งคืน; } / ** * ตั้งค่าข้อมูลการอนุญาต * * @param ผู้ใช้ * / โมฆะสาธารณะ setAuthorize (ผู้ใช้ผู้ใช้) {Authorize Authorize = this.upMclient.getAuthorize (user.getId ()); user.setRoles (Authorize.getRoles ()); user.setResources (Authorize.getResources ()); } ส่วนตัว USERVO Authenticate (IntegrationAuthentication IntegrationAuthentication) {ถ้า (this.Authenticators! = null) {สำหรับ (IntegrationAuthenticator Authenticator: Authenticators) {ถ้า (Authenticator.support (Integrationauthentication)) }} return null; -นี่คือ IntegrationUserDetailsService วิธีการรับรองความถูกต้องจะถูกเรียกในวิธีการโหลด ในวิธีการรับรองความถูกต้องประเภทการตรวจสอบบริบทปัจจุบันจะเรียก IntegrationAuthenticator ที่แตกต่างกันเพื่อรับข้อมูลผู้ใช้ มาดูกันว่าชื่อผู้ใช้และรหัสผ่านเริ่มต้นได้รับการจัดการอย่างไร:
@component @primarypublic class usernamepasswordauthenticator ขยายบทคัดย่อ preparepareintegrationauthenticator {@autowired ส่วนตัว Ucclient Ucclient; @Override การรับรองความถูกต้องของ USERVO สาธารณะ (IntegrationAuthentication IntegrationAuthentication) {return Ucclient.finduserByUsername (IntegrationAuthentication.getUserName ()); } @Override โมฆะสาธารณะเตรียม (IntegrationAuthentication IntegrationAuthentication) {} @Override การสนับสนุนบูลีนสาธารณะ (IntegrationAuthentication Integrationauthentication) {return stringutils.isempty (Integrationauthentication.getauthtype ()); -USERNAMEPASSWORDAUTHENTICATOR จะจัดการเฉพาะประเภทการรับรองความถูกต้องเริ่มต้นโดยไม่ต้องระบุประเภทการรับรองความถูกต้องที่ระบุ ชั้นเรียนนี้ส่วนใหญ่จะได้รับรหัสผ่านผ่านชื่อผู้ใช้ ถัดไปมาดูวิธีจัดการกับการเข้าสู่ระบบรหัสตรวจสอบรูปภาพ:
/*** การตรวจสอบรหัสการตรวจสอบแบบบูรณาการ* @author liqiu* @date 2018-3-31 **/ @componentPublic คลาส VerificationCodeIntegrationAuthenticator ขยาย UserNamePasswordAtorator @autowired VCCClient VCCClient; @Override โมฆะสาธารณะเตรียม (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 ()) {โยน OAuth2Exception ใหม่ ("ข้อผิดพลาดรหัสการตรวจสอบ"); }} @Override การสนับสนุนบูลีนสาธารณะ (IntegrationAuthentication Integrationauthentication) {return verification_code_auth_type.equals (Integrationauthentication.getauthtype ()); -VerificationCodeInTeGrationAuthenticator สืบทอด USERNAMEPASSWORDAUTHENTICATOR เพราะจำเป็นต้องตรวจสอบว่ารหัสการตรวจสอบนั้นถูกต้องในวิธีการเตรียมการหรือไม่และผู้ใช้ได้รับโดยใช้ชื่อผู้ใช้และรหัสผ่าน อย่างไรก็ตามประเภทการรับรองความถูกต้องคือ "VC" ก่อนที่จะสามารถประมวลผลได้ ลองมาดูกันว่าการจัดการรหัสการตรวจสอบ SMS ได้รับการจัดการอย่างไร:
@componentpublic คลาส SMSIntegrationAuthenticator ขยายบทคัดย่อ PRACTIONPREAPLEATIONITEGRATIONAUTHENTICATOR ApplicationEventPublisherAware {@autowired ส่วนตัว Ucclient Ucclient; @autowired VCCClient VCCClient; @AutoWired รหัสผ่านส่วนตัวรหัสผ่านรหัสผ่าน; แอปพลิเคชันส่วนตัว EVENTPUBLISHER ApplicationEventPublisher; สตริงคงสุดท้ายส่วนตัว sms_auth_type = "sms"; @Override การรับรองความถูกต้องของ USERVO สาธารณะ (IntegrationAuthentication IntegrationAuthentication) {// รับรหัสผ่านค่าที่แท้จริงคือรหัสผ่านรหัสการตรวจสอบรหัสผ่าน = IntegrationAuthentication.getAuthParameter ("รหัสผ่าน"); // รับชื่อผู้ใช้ค่าจริงคือสตริงหมายเลขโทรศัพท์มือถือชื่อผู้ใช้ = IntegrationAuthentication.getUserName (); // เผยแพร่กิจกรรมคุณสามารถฟังกิจกรรมเพื่อลงทะเบียนผู้ใช้โดยอัตโนมัติสิ่งนี้ ApplicationEventPublisher.PublisheVent (ใหม่ SMSAuthenticateBeHoreEvent (IntegrationAuthentication)); // ผู้ใช้สอบถามผ่านหมายเลขโทรศัพท์มือถือ uservo uservo = this.ucclient.finduserbyphonenumber (ชื่อผู้ใช้); if (uservo! = null) {// ตั้งรหัสผ่านเป็นรหัสการตรวจสอบ uservo.setPassword (passwordencoder.encode (รหัสผ่าน)); // เผยแพร่กิจกรรมคุณสามารถฟังเหตุการณ์เพื่อการแจ้งเตือนข้อความนี้ ApplicationEventPublisher.PublisheVent (SMSAuthenticatesuccessEvent ใหม่ (IntegrationAuthentication)); } return uservo; } @Override โมฆะสาธารณะเตรียม (IntegrationAuthentication IntegrationAuthentication) {String smstoken = IntegrationAuthentication.getAuthParameter ("SMS_Token"); String SMSCODE = IntegrationAuthentication.getAuthParameter ("รหัสผ่าน"); String username = IntegrationAuthentication.getAuthParameter ("ชื่อผู้ใช้"); ผลลัพธ์ <boolean> result = vccclient.validate (smstoken, smscode, ชื่อผู้ใช้); if (! result.getData ()) {โยน OAuth2Exception ใหม่ ("ข้อผิดพลาดรหัสการตรวจสอบหรือหมดอายุ"); }} @Override การสนับสนุนบูลีนสาธารณะ (IntegrationAuthentication Integrationauthentication) {return sms_auth_type.equals (Integrationauthentication.getauthtype ()); } @Override โมฆะสาธารณะ setApplicationEventPublisher (ApplicationEventPublisher ApplicationEventPublisher) {this.applicationEventPublisher = ApplicationEventPublisher; -SMSIntegrationAuthenticator จะประมวลผลรหัสการตรวจสอบ SMS ที่บันทึกไว้ล่วงหน้าเพื่อตรวจสอบว่าผิดกฎหมายหรือไม่ หากมันผิดกฎหมายมันจะขัดจังหวะการเข้าสู่ระบบโดยตรง หากผ่านการประมวลผลล่วงหน้าข้อมูลผู้ใช้จะได้รับผ่านหมายเลขโทรศัพท์มือถือเมื่อได้รับข้อมูลผู้ใช้และรหัสผ่านจะถูกรีเซ็ตเพื่อผ่านการตรวจสอบรหัสผ่านที่ตามมา
สรุป
ในโซลูชันนี้การใช้งานหลักของรูปแบบการออกแบบห่วงโซ่ความรับผิดชอบและอะแดปเตอร์เพื่อแก้ปัญหาการเข้าสู่ระบบแบบบูรณาการช่วยเพิ่มความสามารถในการปรับขนาดและไม่ก่อให้เกิดมลพิษซอร์สโค้ดของฤดูใบไม้ผลิ หากคุณต้องการสืบทอดการเข้าสู่ระบบอื่น ๆ คุณจะต้องใช้การรวมกลุ่มที่กำหนดเองเท่านั้น
ที่อยู่โครงการ: https://gitee.com/leecho/cola-cloud
ดาวน์โหลดท้องถิ่น: cola-cloud_jb51.rar
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น