JWT (JSON Web Token) เป็น Open Standard Open Standard (RFC 7519) ที่ใช้ JSON (RFC 7519) เพื่อผ่านการเรียกร้องระหว่างสภาพแวดล้อมแอปพลิเคชันเครือข่าย โทเค็นได้รับการออกแบบให้มีขนาดกะทัดรัดและปลอดภัยโดยเฉพาะอย่างยิ่งเหมาะสำหรับสถานการณ์การลงชื่อเข้าใช้ครั้งเดียว (SSO) ของไซต์กระจาย โดยทั่วไปคำสั่ง JWT จะใช้เพื่อส่งผ่านข้อมูลประจำตัวผู้ใช้ที่ผ่านการรับรองความถูกต้องระหว่างผู้ให้บริการข้อมูลประจำตัวและผู้ให้บริการเพื่ออำนวยความสะดวกในการได้มาซึ่งทรัพยากรจากเซิร์ฟเวอร์ทรัพยากร นอกจากนี้ยังสามารถเพิ่มข้อมูลการประกาศเพิ่มเติมที่จำเป็นสำหรับตรรกะทางธุรกิจอื่น ๆ โทเค็นยังสามารถใช้โดยตรงสำหรับการตรวจสอบหรือเข้ารหัส
โดยปกติแล้วจะมีความเสี่ยงมากที่จะเปิดเผย API โดยตรง หากคุณไม่ได้พูดถึงสิ่งอื่นใดคุณสามารถดื่มได้หากคุณถูกโจมตีโดยตรงโดยเครื่อง โดยทั่วไปแล้วระดับการอนุญาตบางอย่างจะต้องถูกแบ่งออกเป็น API จากนั้นการตรวจสอบผู้ใช้จะเสร็จสิ้นและ API ที่เกี่ยวข้องจะถูกมอบให้กับผู้ใช้ตามผลการตรวจสอบความถูกต้อง ในปัจจุบันมีโซลูชั่นกระแสหลักอีกหลายประการ:
OAuth เป็นมาตรฐานการอนุญาตแบบเปิดที่อนุญาตให้ผู้ใช้อนุญาตให้แอปพลิเคชันบุคคลที่สามเข้าถึงทรัพยากรส่วนตัว (เช่นภาพถ่ายวิดีโอ) ที่ผู้ใช้เก็บไว้ในบริการโดยไม่ต้องให้ชื่อผู้ใช้และรหัสผ่านแก่แอปพลิเคชันบุคคลที่สาม
OAuth อนุญาตให้ผู้ใช้ให้โทเค็นแทนชื่อผู้ใช้และรหัสผ่านเพื่อเข้าถึงข้อมูลที่เก็บไว้ในผู้ให้บริการเฉพาะ โทเค็นแต่ละตัวอนุญาตระบบของบุคคลที่สามเฉพาะ (เช่นเว็บไซต์แก้ไขวิดีโอ) เพื่อเข้าถึงทรัพยากรเฉพาะ (เช่นวิดีโอในอัลบั้มที่แน่นอน) ภายในระยะเวลาที่กำหนด (เช่นภายใน 2 ชั่วโมงข้างหน้า) ด้วยวิธีนี้ OAuth อนุญาตให้ผู้ใช้อนุญาตเว็บไซต์บุคคลที่สามเพื่อเข้าถึงข้อมูลเฉพาะบางอย่างที่พวกเขาเก็บไว้ในผู้ให้บริการรายอื่นแทนที่จะเป็นเนื้อหาทั้งหมด
กลไกการรับรองความถูกต้องของคุกกี้คือการสร้างวัตถุเซสชันบนเซิร์ฟเวอร์สำหรับการร้องขอการรับรองความถูกต้องและในเวลาเดียวกันสร้างวัตถุคุกกี้บนเบราว์เซอร์ของไคลเอนต์ วัตถุคุกกี้ถูกนำไปยังไคลเอนต์เพื่อจับคู่วัตถุเซสชันบนเซิร์ฟเวอร์เพื่อให้ได้การจัดการสถานะ โดยค่าเริ่มต้นคุกกี้จะถูกลบเมื่อเราปิดเบราว์เซอร์ อย่างไรก็ตามคุณสามารถปรับเปลี่ยนเวลาหมดอายุของคุกกี้เพื่อให้คุกกี้ใช้ได้ในช่วงระยะเวลาหนึ่ง การรับรองความถูกต้องตามวิธีการเซสชันจะต้องกดดันเซิร์ฟเวอร์ (หน่วยความจำที่เก็บข้อมูล) อย่างหลีกเลี่ยงไม่ได้ไม่ใช่เรื่องง่ายที่จะขยาย (ต้องจัดการเซสชันแบบกระจาย)
1. เปรียบเทียบกับเซสชันไม่จำเป็นต้องบันทึกบนเซิร์ฟเวอร์และไม่ได้ครอบครองหน่วยความจำเซิร์ฟเวอร์ค่าใช้จ่าย
2. ไร้สัญชาติและปรับขนาดได้สูง: ตัวอย่างเช่นมี 3 เครื่อง (A, B, C) เพื่อสร้างคลัสเตอร์เซิร์ฟเวอร์ หากเซสชันมีอยู่ในเครื่อง A เซสชั่นสามารถบันทึกไว้ในเซิร์ฟเวอร์ใดเซสชันเท่านั้น ในเวลานี้คุณไม่สามารถเข้าถึงเครื่อง B และ C ได้เนื่องจากเซสชันไม่ได้เก็บไว้ใน B และ C และการใช้โทเค็นสามารถตรวจสอบความถูกต้องตามกฎหมายของคำขอของผู้ใช้ ไม่เป็นไรสำหรับฉันที่จะเพิ่มเครื่องจักรอีกสองสามเครื่องดังนั้นนี่คือความหมาย
3. การแยกส่วนหน้าและรองรับการเข้าถึงข้ามโดเมน
- องค์ประกอบของ JWT
{"ISS": "JWT Builder", "IAT": 1416797419, "Exp": 14483333419, "Aud": "www.battcn.com", "sub": "[email protected]", " "[email protected]", "บทบาท": ["ผู้ดูแลระบบ", "สมาชิก"]}JWT เป็นสตริงจริง ๆ ซึ่งประกอบด้วยสามส่วนส่วนหัว, น้ำหนักบรรทุกและลายเซ็น (เรียงลำดับตามลำดับในภาพด้านบน)
เครื่องกำเนิดโทเค็น JWT: https://jwt.io/
- การตรวจสอบเข้าสู่ระบบ
- ขอการรับรองความถูกต้อง
โทเค็นที่ไม่ถูกต้อง
โทเค็นที่ถูกต้อง
มีข้อดีและข้อเสีย ไม่ว่าจะเป็นสิ่งที่เกี่ยวข้องควรได้รับการพิจารณาอย่างชัดเจนแทนที่จะเป็นเทคโนโลยีและสไตล์
การแมปคีย์ tokenproperties พร้อมทรัพยากร application.yml ใช้งานง่าย
@configuration@configurationProperties (prefix = "battcn.security.token") คลาสสาธารณะ tokenproperties { / *** {@link com.battcn.security.model.token.token} เวลาหมดอายุ / *** ผู้ออก*/ ผู้ออกสตริงส่วนตัว; /*** รหัสที่ใช้ลายเซ็น {@link com.battcn.security.model.token.token} */ สตริงส่วนตัวลงนาม / *** {@link com.battcn.security.model.token.token} การรีเฟรชเวลาหมดอายุ*/ Integer Private Integer Refresexptime; // รับชุด ... } ชั้นเรียนที่สร้างโดยโทเค็น
@ComponentPublic Class TokenFactory {Private Final TokenProperties คุณสมบัติ; @autowired สาธารณะ tokenfactory (คุณสมบัติ tokenproperties) {this.properties = คุณสมบัติ; } / ** * ใช้ jjwt เพื่อสร้างโทเค็น * @param บริบท * @return * / Public AccessToken CreateAccessToken (บริบท userContext) {potoral.ofnullable (context.get.getUserName ()). ORELSETHROW ()- ตัวเลือก. ofnullable (context.getAuthorities ()). ORELESTHROW (()-> ใหม่ที่ผิดกฎหมาย EllegalArgumentException ("ผู้ใช้ไม่มีสิทธิ์ใด ๆ ")); การเรียกร้องการเรียกร้อง = jwts.claims (). setSubject (context.getUserName ()); cialens.put ("scopes", context.getauthorities (). stream (). แผนที่ (วัตถุ :: toString) .collect (tolist ())); localDateTime currentTime = localDatetime.now (); String token = jwts.builder () .setClaims (การเรียกร้อง) .setissuer (properties.getissuer ()) .setissuedat (วันที่ (currenttime.atzone (zoneid.systemdefault (). toinstant ()). .atzone (zoneid.systemdefault ()). toinstant ())) .Signwith (signaturealgorithm.hs512, properties.getSigningKey ()) .COMPACT (); ส่งคืน AccessToken ใหม่ (โทเค็นการเรียกร้อง); } / ** * สร้างและรีเฟรชรีเฟรช * @param usercontext * @return * / โทเค็นสาธารณะ } localDateTime currentTime = localDateTime.now (); การเรียกร้องการเรียกร้อง = jwts.claims (). setSubject (userContext.getUserName ()); cialenss.put ("scopes", array.aslist (scopes.refresh_token.authority ())); String token = jwts.builder () .setClaims (การเรียกร้อง) .setIssuer (properties.getissuer ()) .setId (uuid.randomuuid (). toString () .setissuedat (วันที่ .plusminutes (properties.getRefreSexptime ())) .atzone (zoneid.systemdefault ()). toinstant ())) .Signwith (Signaturealgorithm.hs512, properties.getSigningKey ()) ส่งคืน AccessToken ใหม่ (โทเค็นการเรียกร้อง); - ไฟล์การกำหนดค่ารวมถึงเวลาหมดอายุโทเค็นรหัสลับสามารถขยายได้ด้วยตัวเอง
battcn: ความปลอดภัย: โทเค็น: หมดอายุเวลา: 10 # นาที 1440 Refresh-exp-time: 30 # นาทีที่ 2880 ผู้ออก: http://blog.battcn.com Signing-key: battcn
WebSecurityConfig เป็นการกำหนดค่าหลักของความปลอดภัยในสปริง ในการรักษาความปลอดภัยโดยทั่วไปเราสามารถใช้ฟังก์ชั่นที่เราต้องการได้โดยการกำหนดตัวกรอง
@configuration@enablewebsecuritypublic คลาส websecurityconfig ขยาย websecurityconfigureradapter {สตริงสุดท้ายคงที่ token_header_param = "x-uthorization"; สตริงสุดท้ายคงที่สาธารณะ form_based_login_entry_point = "/api/auth/login"; สตริงสุดท้ายคงที่สาธารณะ token_based_auth_entry_point = "/api/**"; สตริงสุดท้ายคงที่สาธารณะจัดการ _token_based_auth_entry_point = "/จัดการ/**"; สตริงสุดท้ายคงที่สาธารณะ TOKEN_REFRESH_ENTRY_POINT = "/API/AUTH/TOKEN"; @autowired ส่วนตัว restauthenticationEntryPoint การรับรองความถูกต้องของจุด @autowired AuthenticationsuccessHandler SuccessHandler; @autowired AuthenticationFailureHandler FailureHandler; @autowired ส่วนตัว loginauthenticationprovider loginauthenticationprovider; @autowired ส่วนตัว TokenauthenticationProvider TokenauthenticationProvider; @autowired Tokenextractor Tokenextractor; @autowired AuthenticationManager AuthenticationManager; Protected LoginProcessingFilter buildloginProcessingFilter () โยนข้อยกเว้น {loginProcessingFilter ตัวกรอง = ใหม่ loginProcessingFilter (form_based_login_point_point, SuccessHandler, FailureHer Filter.setAuthenticationManager (this.authenticationManager); ตัวกรองส่งคืน; } ได้รับการปกป้อง tokenauthenticationProcessingFilter buildTokenauthenticationProcessingFilter () โยนข้อยกเว้น {รายการ <String> list = lists.newarrayList (token_based_auth_point_point, manague_token_based_auth_entry_point); skippathrequestmatcher matcher = ใหม่ skippathrequestmatcher (รายการ); TokenauthenticationProcessingFilter ตัวกรอง = New TokenauthenticationProcessingFilter (FailureHandler, Tokenextractor, Matcher); Filter.setAuthenticationManager (this.authenticationManager); ตัวกรองส่งคืน; } @Bean @Override AuthenticationManager AuthenticationManagerBean () โยนข้อยกเว้น {return super.authenticationManagerBean (); } @Override Void Protected Configure (AuthenticationManagerBuilder Auth) {auth.authenticationProvider (loginauthenticationProvider); Auth.AuthenticationProvider (TokenauthenticationProvider); } @Override Void Protected Configure (httpsecurity http) โยนข้อยกเว้น {http .csrf (). disable () // เพราะมันใช้ JWT คุณสามารถปิด csrf ได้ที่นี่ ExceptionHandling () .SessionCreationPolicy (SessionCreationPolicy.Stateless). และ () .AuthorizeRequests () .AntMatchers (form_based_login_point_point) .permitall () // การเข้าสู่ระบบจุดสิ้นสุด .authorizeRequests () .AntMatchers (TOKEN_BASD_AUTH_ENTRY_POINT) .Authenticated () // การป้องกัน API end-points .AntMatchers (manaling_token_based_auth_entry_point) .hasanyrole .addfilterbefore (buildloginprocessingFilter (), usernamepasswordauthenticationfilter.class) .addfilterbefore (buildTokenauthenticationProcessingFilter () -เนื่องจากรหัส JWT ถูกห่อหุ้มและมีเนื้อหาจำนวนมากจึงมีเพียงชิ้นส่วนหลักเท่านั้นที่โพสต์ไว้ในบทความ หากจำเป็นต้องใช้รหัสที่สมบูรณ์คุณสามารถรับได้โดยตรงจาก Git ต่อไปนี้
รหัสของบทนี้ (battcn-jwt-service): http://xiazai.vevb.com/201801/yuanma/battcn-cloud_jb51.rar
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น