การแนะนำพื้นฐานความปลอดภัยของฤดูใบไม้ผลิ
ฉันจะไม่แนะนำความปลอดภัยในฤดูใบไม้ผลิมากเกินไปที่นี่ สำหรับรายละเอียดโปรดดูเอกสารอย่างเป็นทางการ
ฉันจะพูดถึงฟังก์ชั่นหลักของ Springsecurity เท่านั้น:
การก่อสร้างสภาพแวดล้อมขั้นพื้นฐาน
ที่นี่เราใช้ Springboot เป็นกรอบพื้นฐานของโครงการ ฉันใช้วิธี Maven สำหรับการจัดการแพ็คเกจดังนั้นที่นี่ก่อนอื่นเราให้วิธีการรวมความปลอดภัยของฤดูใบไม้ผลิ
<การพึ่งพา> ... <การพึ่งพา> <roupId> org.springframework.boot </groupid> <ratifactId> Spring-Boot-Starter-Security </artifactid> </derpendency> ...
จากนั้นสร้างอินเทอร์เฟซคำขอเว็บเลเยอร์
@restController @requestmapping ("/ผู้ใช้") คลาสสาธารณะ userController {@getMapping สตริงสาธารณะ getusers () {return "Hello Spring Security"; -ถัดไปคุณสามารถเรียกใช้โครงการโดยตรงและโทรหาอินเทอร์เฟซเพื่อดูเอฟเฟกต์
การโทรผ่านหน้าเว็บ
ก่อนอื่นเราทำการโทรผ่านเบราว์เซอร์และเข้าถึง http: // localhost: 8080/ผู้ใช้โดยตรง หากสามารถเข้าถึงอินเทอร์เฟซได้ตามปกติควรแสดง "Hello Spring Security"
แต่เราไม่สามารถเข้าถึงได้ตามปกติและกล่องป้อนข้อมูลการรับรองความถูกต้องในรูปด้านล่างจะปรากฏขึ้น
นี่เป็นเพราะใน Springboot ความปลอดภัยของสปริงเริ่มต้นมีผลบังคับใช้ ในเวลานี้อินเทอร์เฟซได้รับการปกป้องและเราจำเป็นต้องผ่านการตรวจสอบเพื่อเข้าถึงตามปกติ Spring Security ให้ผู้ใช้เริ่มต้นชื่อผู้ใช้คือผู้ใช้และรหัสผ่านจะถูกสร้างขึ้นโดยอัตโนมัติเมื่อเริ่มโครงการ
เมื่อเราตรวจสอบบันทึกการเริ่มต้นโครงการเราจะพบบันทึกต่อไปนี้
การใช้รหัสผ่านความปลอดภัยเริ่มต้น: 62CCF9CA-9FBE-4993-8566-8468CC33C28C
แน่นอนรหัสผ่านที่คุณเห็นต้องแตกต่างจากของฉัน เราเข้าสู่ระบบโดยตรงกับผู้ใช้และรหัสผ่านในบันทึกการเริ่มต้น
หลังจากลงชื่อเข้าใช้สำเร็จคุณจะข้ามไปที่หน้าเว็บที่เรียกว่าอินเทอร์เฟซตามปกติ
หากคุณไม่ต้องการเปิดใช้งาน Spring Security ตั้งแต่ต้นคุณสามารถกำหนดค่าต่อไปนี้ในไฟล์กำหนดค่า:
# ความปลอดภัยเปิดใช้งาน security.basic.enabled = false
กล่องเข้าสู่ระบบที่ฉันเพิ่งเห็นนั้นจัดทำโดย Springsecurity ซึ่งเรียกว่า httpbasiclogin ไม่ใช่สิ่งที่เราต้องการในผลิตภัณฑ์ของเรา ส่วนหน้าของเราโดยทั่วไปดำเนินการตรวจสอบการเข้าสู่ระบบของผู้ใช้ผ่านการส่งแบบฟอร์มดังนั้นเราจำเป็นต้องปรับแต่งตรรกะการตรวจสอบของเราเอง
ปรับแต่งตรรกะการรับรองความถูกต้องของผู้ใช้
แต่ละระบบจะต้องมีชุดระบบผู้ใช้ของตัวเองดังนั้นเราจึงจำเป็นต้องปรับแต่งตรรกะการตรวจสอบความถูกต้องของเราเองและอินเทอร์เฟซเข้าสู่ระบบ
ที่นี่เราจำเป็นต้องกำหนดค่า Springsecurity ตามลำดับ
@ConfigurationPublic คลาส BrowerSecurityConfig ขยาย websecurityConfigurerAdapter {@Override void protected void กำหนดค่า (httpsecurity http) โยนข้อยกเว้น {http.formlogin () // กำหนดหน้าเข้าสู่ระบบ และสิ่งใดที่ไม่จำเป็นต้องได้รับการปกป้องใด ๆ () // สำหรับคำขอใด ๆ คุณสามารถเข้าถึง. Authenticated (); -ถัดไปกำหนดค่าตรรกะการตรวจสอบผู้ใช้เพราะเรามีระบบผู้ใช้ของเราเอง
@ComponentPublic Class MyUserDetailsService ดำเนินการ UserDetailsService {Private Logger Logger = loggerFactory.getLogger (getClass ()); @Override UserDetails LoadUserByUserName (ชื่อผู้ใช้สตริง) โยน USERNAMENOTFoundException {logger.info ("ชื่อผู้ใช้ของผู้ใช้: {}" ชื่อผู้ใช้); // todo ตามชื่อผู้ใช้ค้นหารหัสผ่านที่เกี่ยวข้องและห่อหุ้มข้อมูลผู้ใช้และส่งคืน พารามิเตอร์คือ: ชื่อผู้ใช้, รหัสผ่าน, ผู้ใช้สิทธิ์ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (ผู้ใช้ชื่อ "123456", AuthorAtutils.CommaseParatedStringToAuthorityList ("ผู้ดูแลระบบ")); ผู้ใช้ส่งคืน; - เราไม่ได้ทำการตรวจสอบมากเกินไปที่นี่ ชื่อผู้ใช้สามารถกรอกได้ตามต้องการ แต่รหัสผ่านจะต้องเป็น "123456" เพื่อให้เราสามารถเข้าสู่ระบบได้สำเร็จ
ในเวลาเดียวกันเราจะเห็นว่าพารามิเตอร์ที่สามของวัตถุผู้ใช้ที่นี่แสดงถึงการอนุญาตของผู้ใช้ปัจจุบันและเราตั้งค่าเป็น "ผู้ดูแลระบบ"
เรียกใช้โปรแกรมเพื่อทดสอบและคุณจะพบว่าอินเทอร์เฟซเข้าสู่ระบบมีการเปลี่ยนแปลง
นี่เป็นเพราะเรากำหนดค่า http.formLogin() ในไฟล์การกำหนดค่า
มาเติมผู้ใช้ที่นี่กันแล้วกรอกข้อมูลที่ผิด (ไม่ใช่ 123456) สิ่งนี้จะแจ้งข้อผิดพลาดในการตรวจสอบ:
ในเวลาเดียวกันบนคอนโซลผู้ใช้ที่คุณเพิ่งกรอกข้อมูลเมื่อคุณเข้าสู่ระบบจะถูกพิมพ์ออกมา
ตอนนี้ลองเข้าสู่ระบบด้วยรหัสผ่านที่ถูกต้อง คุณสามารถพบว่ามันจะผ่านการตรวจสอบและข้ามไปยังหน้าการโทรอินเตอร์เฟสที่ถูกต้อง
ผู้ใช้รายละเอียด
ตอนนี้เมื่อเราเขียน MyUserDetailsService เราใช้วิธีการและส่งคืน UserDetails ผู้ใช้งานนี้เป็นวัตถุที่ห่อหุ้มข้อมูลผู้ใช้ซึ่งมีเจ็ดวิธี
ส่วนต่อประสานสาธารณะผู้ใช้งานช่วยขยาย serializable {// การรวบรวมข้อมูลการอนุญาตที่ห่อหุ้มด้วย <? ขยาย Grantedauthority> getAuthorities (); // รหัสผ่านข้อมูลสตริง getPassword (); // เข้าสู่ระบบสตริงชื่อผู้ใช้ getUserName (); // ไม่ว่าบัญชีจะหมดอายุบูลีน isaccountnonexpired (); // ไม่ว่าบัญชีจะเป็นบูลีนแช่แข็ง isaccountnonlocked (); // ไม่ว่ารหัสผ่านบัญชีจะหมดอายุหรือไม่โดยทั่วไประบบบางระบบที่มีข้อกำหนดรหัสผ่านสูงจะใช้ เมื่อเทียบกับผู้ใช้จะต้องรีเซ็ตรหัสผ่านทุกครั้งในขณะที่บูลีน iscredentialsentsnonexpired (); // มีบัญชีหรือไม่? บูลีน isenabled ();}เมื่อเราส่งคืนผู้ใช้ระดับการใช้งาน UserDetails เราสามารถตั้งค่าพารามิเตอร์ที่สอดคล้องกันผ่านวิธีตัวสร้างผู้ใช้
การเข้ารหัสรหัสผ่านและการถอดรหัส
มีอินเทอร์เฟซรหัสผ่านรหัสผ่านในสปริงส์ความปลอดภัย
Public Interface PasswordEncoder {// เข้ารหัสสตริงรหัสผ่านเข้ารหัส (Charsequence VAR1); // กำหนดรหัสผ่านเพื่อให้ตรงกับการจับคู่บูลีน (charsequence var1, string var2);} เราเพียงแค่ต้องใช้อินเทอร์เฟซนี้ด้วยตนเองและกำหนดค่าในไฟล์การกำหนดค่า
ที่นี่ฉันจะทดสอบชั่วคราวด้วยคลาสการใช้งานโดยค่าเริ่มต้น
// BrowersecurityConfig @BeanPublic PasswordEncoder PasswordEncoder () {ส่งคืน bcryptpasswordencoder ใหม่ (); -การใช้การเข้ารหัส:
@ComponentPublic Class MyUserDetailsService ดำเนินการ UserDetailsService {Private Logger Logger = loggerFactory.getLogger (getClass ()); @AutoWired รหัสผ่านส่วนตัวรหัสผ่านรหัสผ่าน; @Override UserDetails LoadUserByUserName (ชื่อผู้ใช้สตริง) โยน USERNAMENOTFoundException {logger.info ("ชื่อผู้ใช้ของผู้ใช้: {}" ชื่อผู้ใช้); String Password = PasswordEncoder.encode ("123456"); logger.info ("รหัสผ่าน: {}", รหัสผ่าน); // พารามิเตอร์คือ: ชื่อผู้ใช้, รหัสผ่าน, ผู้ใช้สิทธิ์ผู้ใช้ = ผู้ใช้ใหม่ (ชื่อผู้ใช้, รหัสผ่าน, AuthorAtutils.CommaseparatedStringToAuthorityList ("ผู้ดูแลระบบ")); ผู้ใช้ส่งคืน; -ที่นี่เราเข้ารหัส 123456 เราสามารถทำการทดสอบและพบว่ารหัสผ่านที่พิมพ์ในแต่ละครั้งแตกต่างกัน นี่คือบทบาทของ bcryptpasswordencoder ที่กำหนดค่า
ตรรกะการรับรองความถูกต้องของผู้ใช้ส่วนบุคคล
หน้าเข้าสู่ระบบที่กำหนดเอง
ในการทดสอบก่อนหน้านี้อินเทอร์เฟซเข้าสู่ระบบเริ่มต้นมีการใช้งานอยู่เสมอ ฉันเชื่อว่าแต่ละผลิตภัณฑ์มีการออกแบบอินเทอร์เฟซเข้าสู่ระบบของตัวเองดังนั้นเราจะได้เรียนรู้เกี่ยวกับวิธีการปรับแต่งหน้าเข้าสู่ระบบในส่วนนี้
มาเขียนหน้าเข้าสู่ระบบง่ายๆก่อน
<! doctype html> <html lang = "en"> <head> <meta charset = "utf-8"> <title> หน้าเข้าสู่ระบบ </title> </head> <body> <h2> หน้าล็อกอินที่กำหนดเอง </h2> <form action = "ผู้ใช้/ล็อกอิน" type = "text" name = "username"> </td> </tr> <tr> <td> รหัสผ่าน: </td> <td> <อินพุต type = "รหัสผ่าน" name = "รหัสผ่าน"> </td> </tr> <tr> <td Colspan = "2"> <button type = "ส่ง"
หลังจากเสร็จสิ้นหน้าเข้าสู่ระบบคุณจะต้องกำหนดค่าเพื่อความปลอดภัยของสปริงส์
// BrowersecurityConfig.java@overrideprotected Void Configure (httpsecurity http) พ่นข้อยกเว้น {http.formlogin () // กำหนดหน้าเข้าสู่ระบบที่จะโอนไปยังเมื่อผู้ใช้ต้องการเข้าสู่ระบบ // อินเทอร์เฟซเข้าสู่ระบบที่กำหนดเองและ () .AuthorizeRequests () // กำหนด URL ใดที่ต้องได้รับการปกป้องและไม่จำเป็นต้องได้รับการปกป้อง AantMatchers ("/login.html"). permitall () // กำหนดให้ทุกคนเข้าถึงหน้าเข้าสู่ระบบ // ปิดการป้องกัน CSRF}ด้วยวิธีนี้เมื่อใดก็ตามที่เราเข้าถึงอินเทอร์เฟซที่ได้รับการป้องกันเราจะถูกถ่ายโอนไปยังหน้า login.html
จัดการคำขอประเภทต่างๆ
เนื่องจากตอนนี้ปลายด้านหน้าและด้านหลังจะถูกแยกออกโดยทั่วไปปลายด้านหลังจึงให้อินเทอร์เฟซสำหรับปลายด้านหน้าเพื่อโทรและส่งคืนข้อมูลรูปแบบ JSON ไปยังส่วนหน้า ก่อนหน้านี้มีการเรียกอินเทอร์เฟซที่ได้รับการป้องกันและการกระโดดหน้าถูกเปลี่ยนเส้นทางโดยตรง เป็นที่ยอมรับในด้านเว็บ แต่เป็นไปไม่ได้ในด้านแอพดังนั้นเราจึงต้องทำการประมวลผลเพิ่มเติม
นี่คือความคิดง่ายๆ
ก่อนอื่นให้เขียนคอนโทรลเลอร์ที่กำหนดเองและข้ามไปเมื่อจำเป็นต้องมีการรับรองความถูกต้องของตัวตน
@RestControllerPublic Class BrowsersecurityConitionCorntroller {ตัวบันทึกส่วนตัว logger = loggerFactory.getLogger (getClass ()); // การแคชและการกู้คืนข้อมูลการร้องขอต้นฉบับ requestcache privatecache requestcache = ใหม่ httpsessionRequestCache (); // ใช้เพื่อเปลี่ยนเส้นทางการเปลี่ยนเส้นทางส่วนตัว Redirectstrategy = ใหม่ Defaultredirectstrategy (); /** * เมื่อต้องการการรับรองความถูกต้องของตัวตนให้กระโดดข้าม * @param Request * @param Response * @return */@requestmapping ("/การรับรองความถูกต้อง/ต้องการ") @ResponSestatus (รหัส = httpstatus SavedRequest SavedRequest = requestCache.getRequest (คำขอ, การตอบกลับ); if (savedRequest! = null) {string targetUrl = savedRequest.getRedirecturl (); logger.info ("คำขอที่จะกระตุ้นการกระโดดคือ:" + targetUrl); if (StringUtils.endswithIgnorecase (TargetUrl, ".html")) {redirectstrategy.sendredirect (คำขอ, การตอบสนอง, "/login.html"); }} ส่งคืน BaserEsponse ใหม่ ("บริการที่เข้าถึงได้ต้องมีการรับรองความถูกต้องประจำตัวโปรดแนะนำผู้ใช้ไปยังหน้าเข้าสู่ระบบ"); -แน่นอนว่าไฟล์การกำหนดค่าจะต้องได้รับการแก้ไขตามนั้นดังนั้นฉันจะไม่โพสต์รหัสที่นี่ มันคือการเปิดอินเทอร์เฟซ
ส่วนขยาย:
ที่นี่เราเขียนอินเทอร์เฟซที่เข้าถึงได้จากหน้าเว็บจากนั้นข้ามไปที่หน้า "/login.html" ในความเป็นจริงเราสามารถขยายและกำหนดค่าที่อยู่ JUMP ไปยังไฟล์การกำหนดค่าซึ่งจะสะดวกกว่า
การเข้าสู่ระบบการประมวลผลแบบกำหนดเองสำเร็จ/ล้มเหลว
ในการทดสอบก่อนหน้านี้การเปลี่ยนเส้นทางหน้าจะดำเนินการหลังจากเข้าสู่ระบบที่ประสบความสำเร็จ
ในกรณีของการแยกด้านหน้าและด้านหลังหากเราเข้าสู่ระบบได้สำเร็จเราอาจต้องส่งคืนข้อมูลส่วนบุคคลของผู้ใช้กลับไปที่ส่วนหน้าแทนที่จะกระโดดโดยตรง เช่นเดียวกับการเข้าสู่ระบบที่ล้มเหลว
สิ่งนี้เกี่ยวข้องกับสองอินเทอร์เฟซใน Spring Security AuthenticationSuccessHandler และ AuthenticationFailureHandler เราสามารถใช้อินเทอร์เฟซนี้และกำหนดค่าตามนั้น แน่นอนเฟรมเวิร์กมีคลาสการใช้งานเริ่มต้น เราสามารถสืบทอดคลาสการใช้งานนี้และปรับแต่งธุรกิจของเรา
@Component ("MyAuthenctiationSuccessHandler") คลาสสาธารณะ myauthenctiationsuccesshandler ขยาย SimpleUrlauthenticationsuccessHandler {logger ส่วนตัว logger = loggerFactory.getLogger (getClass ()); @autowired ObjectMapper ObjectMapper; @Override โมฆะสาธารณะ onauthenticationsuccess (คำขอ httpservletrequest, การตอบสนอง httpservletResponse, การตรวจสอบสิทธิ์การตรวจสอบสิทธิ์) พ่น IOException, servletexception {logger.info ("เข้าสู่ระบบสำเร็จ"); Response.SetContentType ("Application/JSON; charset = UTF-8"); Response.getWriter (). เขียน (ObjectMapper.WriteValueEasString (การรับรองความถูกต้อง)); - ที่นี่เราส่งคืนสตริง JSON ผ่านการตอบกลับ
พารามิเตอร์ที่สามในวิธีนี้ Authentication มีข้อมูลผู้ใช้เข้าสู่ระบบ (ผู้ใช้งาน) ข้อมูลเซสชันข้อมูลการเข้าสู่ระบบ ฯลฯ
@Component ("MyAuthenctiationFailureHandler") คลาสสาธารณะ MyauthenctiationFailureHandler ขยาย SimpleUrlauthenticationFailureHandler {Logger ส่วนตัว logger = loggerFactory.getLogger (getClass ()); @autowired ObjectMapper ObjectMapper; @Override โมฆะสาธารณะ onauthenticationFailure (คำขอ httpservletrequest, การตอบสนอง httpservletResponse, ข้อยกเว้นการรับรองความถูกต้อง Exception) โยน ioexception, servletexception {logger.info ("เข้าสู่ระบบล้มเหลว"); Response.setStatus (httpstatus.internal_server_error.value ()); Response.SetContentType ("Application/JSON; charset = UTF-8"); Response.getWriter (). เขียน (ObjectMapper.WriteValueEasString (baseresponse ใหม่ (Exception.getMessage ()))); - พารามิเตอร์ที่สามในวิธีนี้ AuthenticationException รวมถึงข้อมูลเกี่ยวกับความล้มเหลวในการเข้าสู่ระบบ
ในทำนองเดียวกันก็ยังจำเป็นต้องกำหนดค่าในไฟล์การกำหนดค่า ฉันจะไม่โพสต์รหัสทั้งหมดที่นี่เฉพาะข้อความที่เกี่ยวข้องเท่านั้นที่โพสต์
.successhandler (myauthenticationsuccesshandler) // การเข้าสู่ระบบที่กำหนดเองประสบความสำเร็จในการจัดการ FailureHandler (MyauthenticationFailureHandler) // Handles Login Failure Custom
รหัส
คุณสามารถคลิกฉันเพื่อดูรหัสที่สมบูรณ์
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น