บทความนี้บอกเล่าเรื่องราวของการบูต Spring Integrating Spring Security เพื่อใช้การควบคุมการอนุญาตโดยใช้คำอธิบายประกอบในวิธีการและการใช้ผู้ใช้งานที่กำหนดเองเพื่อโหลดข้อมูลผู้ใช้จาก MySQL ใช้การเข้ารหัส MD5 ที่มาพร้อมกับความปลอดภัยเพื่อเข้ารหัสรหัสผ่านของผู้ใช้ เทมเพลตหน้าใช้เครื่องยนต์ thymeleaf
ที่อยู่ซอร์สโค้ด: https://github.com/li5454yong/springboot-security.git
1. แนะนำการพึ่งพา POM
<carent> <menter> org.springframework.boot </groupId> <ratifactId> Spring-Boot-Starter-Parent </artifactid> <version> 1.4.4.Release </เวอร์ชัน> </Parent> <pendencies> <ArtIfactId> Spring-Boot-Starter-WEB </artifactId> </dermentrency> <การพึ่งพา> <roupId> org.springframework.boot </groupId> <ratifactid> Spring-Boot-Starter-Security </artifactid> <ArtifactId> Spring-Security-OAUTH2 </artifactId> </serdency> <การพึ่งพา> <roupId> org.springframework.boot </groupId> <ratifactid> Spring-Boot-Star-Star-thymeLeaf </artifactid> <ArtIfactId> Spring-Boot-Starter-Data-JPA </artifactId> </การพึ่งพาอาศัย> <การพึ่งพา> <roupId> org.springframework.boot </roupid> <ArtIfactId> mysql-connector-java </artifactid> <sersion> 5.1.34 </เวอร์ชัน> </การพึ่งพา> <การพึ่งพาอาศัย> <loupId> com.alibaba </groupId> <ArtifactId> druid </artifactid> <version> 1.0.15
ที่นี่ใช้การรวมการเชื่อมต่อ DRUID และสปริงข้อมูล JPA ใช้การเข้าถึงฐานข้อมูล
2. กำหนดค่าความปลอดภัยของสปริง
@การกำหนดค่า @enableWebMVCSecurity @enableGlobalMethodSecurity (prepOntenabled = true) // เปิดใช้งานการบันทึกความปลอดภัยคลาสสาธารณะคลาสสาธารณะ websecurityConfig ขยาย websecurityConfigurerAdapter {@Bean } @Override Void Protected Configure (httpsecurity http) โยนข้อยกเว้น {// อนุญาตให้ผู้ใช้ทั้งหมดเข้าถึง "/" และ "/home" http.authorizeRequests () .AntMatchers ("/"/home "). permitall () // การเข้าถึงที่อยู่อื่น ๆ // ระบุหน้าเข้าสู่ระบบเป็น "/ล็อกอิน" .loginpage ("/ล็อกอิน") .defaultSuccessurl ("/สวัสดี") // หลังจากเข้าสู่ระบบสำเร็จแล้วให้ข้ามไปที่ "/สวัสดี" โดยค่าเริ่มต้น .permitall () .and () .logout () .logoutsuccessurl ("/home") // URL เริ่มต้นหลังจากการเข้าสู่ระบบคือ "/home" .permitall (); } @AutoWired Public Void ConfigureGlobal (AuthenticationManagerBuilder Auth) โยนข้อยกเว้น {auth .userDetailsService (CustomUserDetailsService ()) } / *** ตั้งค่าวิธีการเข้ารหัสของรหัสผ่านผู้ใช้เป็น MD5 การเข้ารหัส* @return* / @bean สาธารณะ MD5PasswordEncoder รหัสผ่าน () {ส่งคืน MD5PasswordEncoder ใหม่ (); } / *** custom userDetailsService เพื่ออ่านข้อมูลผู้ใช้จากฐานข้อมูล* @return* / @Bean Public CustomUserDetailsService CustomUserDetailsService () {ส่งคืน CustomuserDetailsService ใหม่ (); - มีเพียงการกำหนดค่าพื้นฐานที่ทำไว้ที่นี่ตั้งค่า URL เข้าสู่ระบบ URL ที่กระโดดหลังจากเข้าสู่ระบบประสบความสำเร็จและ URL ที่กระโดดไปที่หลังออกจากระบบ การใช้คำอธิบายประกอบ @enableglobalmethodsecurity (prepostenabled = True) สามารถเปิดใช้งานคำอธิบายประกอบการรักษาความปลอดภัย เราสามารถใช้ @preauthorize และ @prefilter กับวิธีการที่ต้องการการควบคุม
3. ผู้ใช้ที่กำหนดเอง
คลาสสาธารณะ CustomUserDetailsService ใช้ UserDetailsService {@autowired // บริการโดเมนคลาส Suserservice ส่วนตัว Waitservice; @Override UserDetails LoadUserByUserName (String username) พ่น USERNAMENOTFoundException {// SUSER สอดคล้องกับตารางผู้ใช้ในฐานข้อมูลซึ่งเป็นตารางที่เก็บผู้ใช้และรหัสผ่านในที่สุด) if (user == null) {โยน usernamenotfoundException ใหม่ ("ชื่อผู้ใช้" + ชื่อผู้ใช้ + "ไม่พบ"); } // SecurityUser ใช้อีเมลของผู้ใช้และแผนที่ Suser ไปยังผู้ใช้ชื่อผู้ใช้ SecurityUserUserUser = ใหม่ SecurityUser (ผู้ใช้); คอลเลกชัน <SimpleGrantedAuthority> เจ้าหน้าที่ = new ArrayList <SimpleGrantedAuthority> (); change.add (ใหม่ simplegrantedauthority ("role_admin")); ส่งคืน SecurityUser; -ที่นี่คุณจะต้องใช้อินเทอร์เฟซ UserDetailsService เพียงเขียนวิธี LoadUserByUserName ใหม่และดึงข้อมูลผู้ใช้จากฐานข้อมูล ในที่สุดคลาสการใช้งานผู้ใช้งานจะถูกส่งกลับ
4. กำหนดค่าการจัดการข้อผิดพลาด
@ConfigurationPublic Class ErrorPageConfig {@Bean Public EmbeddedServletContainerCustomizer EmbeddedServletContainerCustomizer () {return ใหม่ mycustomizer (); } คลาสสแตติกส่วนตัว Mycustomizer ใช้ EmbeddedServletContainerCustomizer {@Override โมฆะสาธารณะปรับแต่ง (ConfigureDebedDedServletContainer Container) {container.adderRorPages -เมื่อเกิดข้อผิดพลาดในการเข้าถึงให้ข้ามไปที่ "/403"
5. อินเทอร์เฟซคอนโทรลเลอร์
@ControllerPublic Class IndexController {@Resource Private Suserservice Suserservice; @RequestMapping ("/home") Public String Home () {return "Home"; } @preauthorize ("hasrole ('ผู้ใช้')") @requestmapping (value = "/admin", method = requestmethod.get) สตริงสาธารณะ toadmin () {return "helloadmin"; } @RequestMapping ("/hello") สตริงสาธารณะสวัสดี () {return "hello"; } @RequestMapping ("/ล็อกอิน") การเข้าสู่ระบบสตริงสาธารณะ () {return "เข้าสู่ระบบ"; } @RequestMapping ("/") รูทสตริงสาธารณะ () {return "ดัชนี"; } @RequestMapping ("/403") ข้อผิดพลาดสตริงสาธารณะ () {return "403"; -@Preauthorize ("hasrole ('ผู้ใช้')") ใช้กับวิธี Toadmin () ซึ่งบ่งชี้ว่าคุณต้องมีบทบาทผู้ใช้ในการเข้าถึงวิธีนี้ หากคุณต้องการควบคุมระดับการอนุญาตคุณสามารถใช้ @preauthorize ("Haspermission ()") นี่เป็นเพียงหนึ่งในประเพณี สำหรับวิธีการใช้งานเพิ่มเติมคุณสามารถอ่านเอกสารอย่างเป็นทางการได้ ควรสังเกตว่าคำนำหน้าบทบาทเริ่มต้นของความปลอดภัยในสปริงคือ "role_" ซึ่งเพิ่มขึ้นโดยค่าเริ่มต้นเมื่อใช้วิธีการ Hasrole ดังนั้นบทบาทผู้ใช้ของเราในฐานข้อมูลควรเป็น "ROLE_USER" และคำนำหน้าผู้ใช้ "ROLE_" จะถูกเพิ่มก่อนผู้ใช้
6. ทดสอบ
เริ่มโครงการและเยี่ยมชม http: // localhost: 1130/เข้าสู่ระบบ
คลิกเพื่อเข้าสู่ระบบและป้อน "/สวัสดี"
คลิกเพื่อข้ามไปที่หน้าผู้ดูแลระบบ
ในพื้นหลัง URL "/admin" ที่สอดคล้องกับวิธี "ผู้ใช้" ผู้ใช้จะต้องมีบทบาท "ผู้ใช้" ผู้ใช้ที่เข้าสู่ระบบถูกตั้งค่าในฐานข้อมูลเพื่อให้มีบทบาทนี้
ตอนนี้เราปรับเปลี่ยนบทบาทผู้ใช้ในฐานข้อมูลและเปลี่ยนเป็น "role_admin" หลังจากเข้าสู่ระบบแล้วให้เข้าสู่ระบบอีกครั้งคลิกปุ่ม "ไปที่หน้าผู้ดูแลระบบ" อีกครั้งและจะข้ามไปยังหน้าต่อไปนี้
เนื่องจากไม่มีการอนุญาต "ผู้ใช้" ตอนนี้ข้อยกเว้นจึงถูกโยนลงไปในระหว่างการเข้าถึงและมันถูกสกัดกั้นและเปลี่ยนเส้นทางเป็น "/403"
7. การเข้าถึงโพสต์รหัสข้อผิดพลาด 403
ก่อนอื่นเปลี่ยน "/admin" เพื่อโพสต์คำขอ
@Preauthorize ("hasrole ('ผู้ใช้')") @requestmapping (value = "/admin", method = requestMethod.post) สตริงสาธารณะ toadmin () {return "helloadmin"; -เปลี่ยนวิธีการร้องขอของปุ่ม "ไปที่หน้าผู้ดูแลระบบ" จากนิพจน์แบบฟอร์มดั้งเดิมรับการส่งไปยังการส่ง Ajax Post สำหรับสาเหตุที่เราไม่ได้ส่งแบบฟอร์มโพสต์เราจะพูดถึงเรื่องนี้ในภายหลัง แก้ไขรหัสก่อน
<body> <h1 th: inline = "text"> สวัสดี [[$ {#httpservletrequest.remoteuser}]]! </h1> <!-<ฟอร์ม th: action = "@{/logout}" method = "post"> th: type = "ส่ง" th: value = "ไปที่หน้าผู้ดูแลระบบ"/> </form>-> <a th: href = "@{/admin}" rel = "nofollow ภายนอก"> ไปที่หน้าผู้ใช้ผู้ดูแลระบบ </a> <อินพุต th: type = "subment" $ .ajax ({url: "/admin", ประเภท: 'โพสต์', ความสำเร็จ: ฟังก์ชั่น (ข้อมูล) {}}); } </script> คลิกปุ่ม "ไปที่หน้าผู้ดูแลระบบ" และคุณสามารถดูสิ่งต่อไปนี้ในแพลตฟอร์มการดีบัก
นี่เป็นเพราะเฟรมเวิร์กป้องกัน CSRF (คำขอข้ามไซต์การปลอมแปลงคำขอข้ามไซต์) จากการเกิดขึ้นโดยการ จำกัด วิธีการส่วนใหญ่ยกเว้น Get
นี่คือทางออก:
ก่อนอื่นเพิ่มเนื้อหาต่อไปนี้ในแท็ก
<meta name = "_ csrf" th: content = "$ {_ csrf.token}"/> <meta name = "_ csrf_hader" th: content = "$ {_ csrf.headername}" ตราบใดที่มีการเพิ่มโทเค็นนี้พื้นหลังจะตรวจสอบความถูกต้องของโทเค็นนี้ หากถูกต้องจะยอมรับการเข้าถึงโพสต์
จากนั้นเพิ่มรหัสต่อไปนี้ในรหัส AJAX:
var token = $ ('meta [name = "_ csrf"]'). attr ("เนื้อหา"); var header = $ ('meta [name = "_ csrf_hader"]'). attr ("เนื้อหา"); $ (เอกสาร) .ajaxsend (ฟังก์ชั่น (e, xhr, opt) ด้วยวิธีนี้คุณสามารถเข้าถึงได้ตามปกติโดยใช้โพสต์ลบและวิธีอื่น ๆ
ดังกล่าวข้างต้นโดยใช้วิธีการโพสต์ของแบบฟอร์มเพื่อส่ง คุณสามารถดูได้โดยการดูซอร์สโค้ดของหน้า
เฟรมเวิร์กแทรกฟิลด์ที่ซ่อนอยู่ในแบบฟอร์มโดยอัตโนมัติและค่าค่าคือโทเค็นดังนั้นการใช้แบบฟอร์มแบบฟอร์มเพื่อส่งคำขอโพสต์สามารถส่งผ่านโดยตรงและหากคุณส่งใน Ajax Way จะต้องเพิ่มรหัสนั้น
โอเคนั่นคือทั้งหมดที่เกี่ยวกับบทความนี้ จะมีบทความในภายหลังเกี่ยวกับวิธีการใช้ความปลอดภัยในฤดูใบไม้ผลิเพื่อควบคุมการอนุญาตในสไตล์ REST API
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น