ชิโร่
ชิโรเป็นโครงการโอเพ่นซอร์สภายใต้ Apache เราเรียกมันว่า Apache Shiro มันเป็นกรอบความปลอดภัยที่ใช้งานง่ายมากกับโครงการ Java ให้การรับรองความถูกต้องการอนุญาตการเข้ารหัสและการจัดการเซสชัน เช่นเดียวกับความปลอดภัยของฤดูใบไม้ผลิมันเป็นกรอบความปลอดภัยที่ได้รับอนุญาต อย่างไรก็ตามเมื่อเปรียบเทียบกับความปลอดภัยของฤดูใบไม้ผลิชิโร่ใช้วิธีการอนุญาตที่ค่อนข้างง่ายและเข้าใจง่ายและใช้งานง่าย ชิโรเป็นกรอบที่มีน้ำหนักเบา มันง่ายกว่าความปลอดภัยมากและไม่ซับซ้อนเท่าความปลอดภัย สำหรับการแนะนำรายละเอียดเพิ่มเติมโดยทั่วไปคุณสามารถเรียนรู้ได้จากเว็บไซต์ทางการ (http://shiro.apache.org/) ซึ่งส่วนใหญ่มีฟังก์ชั่นต่อไปนี้:
(1) การรับรองความถูกต้อง (การรับรองความถูกต้อง)
(2) การอนุญาต (การอนุญาต)
(3) การจัดการเซสชัน (การจัดการเซสชัน)
(4) การเข้ารหัส (การเข้ารหัส)
ก่อนอื่นบริการตรวจสอบความถูกต้องนั่นคือผ่านเธอคุณสามารถเสร็จสิ้นการรับรองความถูกต้องของตัวตนเพื่อให้เธอสามารถพิจารณาได้ว่าผู้ใช้เป็นสมาชิกจริงหรือไม่
ประการที่สองบริการที่ได้รับอนุญาตที่จะกล่าวอย่างตรงไปตรงมาคือบริการ "การควบคุมการเข้าถึง" นั่นคือให้เธอระบุว่าผู้ใช้มีสิทธิ์อะไรบ้าง เพื่อให้มันตรงไปตรงมามันคือการให้เขาได้รับอนุญาตจากการดำเนินการโดยการตัดสินว่าผู้ใช้มีบทบาทอะไร
จากนั้นมีบริการการจัดการเซสชัน ในเวลานี้กรอบการจัดการเซสชันอิสระแตกต่างจากเซสชัน HTTP ที่เราคุ้นเคย
ในที่สุดเธอก็ให้บริการการเข้ารหัส (เข้ารหัส) ซึ่งห่อหุ้มอัลกอริทึมการเข้ารหัสหลายครั้ง
วันนี้ฉันจะไม่พูดทั้งหมดเกี่ยวกับเรื่องนี้และมุ่งเน้นไปที่ฟังก์ชั่นการจัดการการสนทนาของเธอ อันที่จริงนี่คือสิ่งที่เว็บเกือบทั้งหมดควรมีส่วนร่วม
ก่อนที่จะพูดคุยเกี่ยวกับบริการการจัดการเซสชันของ Shiro ลองทบทวนวิธีการจัดการเซสชันก่อนหน้านี้
1. ในตอนแรกเราใช้กลไกเซสชัน HTTP โดยตรงของเว็บเซิร์ฟเวอร์ นั่นคือถ้าผู้ใช้เข้ามาเป็นครั้งแรกเว็บคอนเทนเนอร์จะสร้างเซสชันสำหรับคำขอแล้วจัดเก็บเซสชัน โดยผ่านเซสชันที่เกี่ยวข้องเป็นคุกกี้ไปยังลูกค้า
หากไคลเอนต์ส่งคำขอไปยังเซิร์ฟเวอร์นี้อีกครั้ง SessionID จะถูกนำมาโดยอัตโนมัติ จากนั้นเว็บเซิร์ฟเวอร์จะพิจารณาว่าเซสชันยังคงอยู่ในหน่วยความจำตาม SessionID ที่นำโดยไคลเอนต์ (เซสชันมีเวลาหมดอายุและสามารถกำหนดค่าได้ในไฟล์ web.xml) หากไม่พบเซสชันที่สอดคล้องกันหมายความว่าเวลาหมดอายุของเซสชันได้ผ่านไปแล้ว ในเวลานี้เว็บเซิร์ฟเวอร์จะสร้างเซสชันอีกครั้งจากนั้นส่งผ่านเซสชันใหม่ไปยังไคลเอนต์เหมือนเดิม
ดังนั้นเราสามารถใช้กลไกนี้เพื่อจัดการเซสชันการเข้าสู่ระบบของผู้ใช้ในโปรแกรม ตัวอย่างเช่นหลังจากการเข้าสู่ระบบครั้งแรกของผู้ใช้สำเร็จแล้วเราจะจัดเก็บข้อมูลพื้นฐานของผู้ใช้ในเซสชัน (ตัวอย่างเช่น: session.setAttribute("user", "userInfo") ) ครั้งต่อไปที่ผู้ใช้เยี่ยมชมอีกครั้งเราจะได้รับข้อมูลผู้ใช้ในเซสชันปัจจุบันตามข้อมูลผู้ใช้
( session.getAttribute("user") ) เพื่อพิจารณาว่าผู้ใช้หมดอายุหรือไม่ หากไม่สามารถรับได้ผู้ใช้จะได้รับแจ้งให้เข้าสู่ระบบอีกครั้ง
2. วิธีที่สองคือการถ่ายโอนสถานที่ที่ข้อมูลถูกเก็บไว้ในสื่อของบุคคลที่สามเช่นแคช, Memecache หรือ Redis วิธีนี้ส่วนใหญ่จะถูกนำมาใช้เนื่องจากการเกิดขึ้นของระบบกระจาย
ในกรณีนี้เราต้องสร้างเซสชันตัวเอง โดยทั่วไปเราจะใช้คำนำหน้าที่กำหนด ( user:login:token ) และเพิ่ม USERID หรือการประทับเวลา จากนั้นเราจะใช้ SessionID นี้เป็นคีย์แคชและข้อมูลของผู้ใช้เป็นค่าและจัดเก็บไว้ในแคชและตั้งเวลาการทำให้เป็นโมฆะ:
jedisclient.set (tokenkey, jsonutil.tojsonstring (userinfo)); jedisclient.expire (tokenkey, token_lose_seconds);
นอกจากนี้เรายังต้องผ่าน tokenkey ที่สร้างขึ้นไปยังลูกค้าผ่านคุกกี้: CookieUtils.setCookie(request, response, "TT_TOKEN", tokenKey);
ด้วยวิธีนี้เมื่อผู้ใช้เข้าชมในครั้งต่อไป (กำหนดตัวดักจับ) เราสามารถนำ tokenkey ที่สอดคล้องกันออกจากคุกกี้แล้วใช้ tokenkey นี้เพื่อไปที่แคชเพื่อดึงค่าที่สอดคล้องกัน หากไม่สามารถรับได้หมายความว่าคีย์หมดอายุและผู้ใช้จะได้รับแจ้งให้เข้าสู่ระบบอีกครั้ง
หมายเหตุ: Tokenkey เป็นสิ่งสำคัญคือฮับที่เชื่อมต่อด้านแคชและไคลเอนต์
3. สิ่งสุดท้ายคือวิธีการชิโรของเราและความคิดนั้นคล้ายกัน รหัสค่อนข้างง่ายดังนั้นฉันจะอัปโหลดรหัส:
1) สร้างไฟล์ ApplicationContext-shiro.xml ใหม่:
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: context = "http://www.springframework xmlns: p = "http://www.springframework.org/schema/p" xmlns: aop = "http://www.springframework.org/schema/tx" xmlns: xsi = "http:/ http:/ XSI: schemalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http:/www.springframwork http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://ww.springframework http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://ww.springframework id = "shirofilter"> <property name = "SecurityManager" ref = "SecurityManager"> </คุณสมบัติ> <property name = "loginurl" value = "/loginPage"> </คุณสมบัติ> <property name = "unauthorizedUrl" value = "/pages/unauthorized.jsp"/> < = anon </value> </property> </ebean> <bean> <property name = "staticMethod" value = "org.apache.shiro.securityutils.setsecurityManager"> </property> <property name = "อาร์กิวเมนต์" ref = "SecurityManager"> ref = "cachemanager"> </property> <property name = "SessionManager" ref = "sessionManager"> </property> </ebean> <bean id = "SessionManager"> <property name = "sessionDao" ref = "SessionDao"> </epean> //
2) กำหนดค่าตัวกรองที่เกี่ยวข้องใน web.xml:
<silter> <filter-name> shirofilter </filter-name> <silter-class> org.springframework.web.filter.delegatingFilterProxy </filter-class> <init-param> <param-name> <silter-mapping> <filter-name> shirofilter </filter-name> <url-pattern>/*</url-pattern> </ตัวกรอง-การแมป>
3) เขียนคลาสการใช้งานสืบทอดบทคัดย่อ abstractsessiondao และใช้วิธีการที่สอดคล้องกัน
แพ็คเกจ com.jdd.core.shiro; นำเข้า com.smart.core.redis.redismanager; นำเข้า org.apache.shiro.session.session; นำเข้า org.apache.shiro.session.unknownsessionexception; นำเข้า org.apache.shiro.session.mgt.eis.eis.eis.eis.eis.eis. org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.util.serializationutils; นำเข้า java.io.*; นำเข้า java.util.arraylist; นำเข้า java.util.collection @Override การอัปเดตโมฆะสาธารณะ (เซสชั่นเซสชัน) พ่น unknownsessionException {redisManager.set (serializationutils.serialize (session.getId (). toString ()), serializationuts.serialize (เซสชัน)); redismanager.expire (serializationutils.serialize (session.getid (). toString ()), 60); } @Override โมฆะสาธารณะลบ (เซสชันเซสชัน) {redisManager.del (serializationutils.serialize (session.getId (). toString ())); } @Override Public Collection <Session> GetActivesessions () {ส่งคืน ArrayList ใหม่ <Session> (); } @Override ป้องกัน serializable docreate (เซสชันเซสชัน) {// นี่คือเมื่อคุณเข้าถึงครั้งแรกสร้าง sessionid serializable sid = this.generatesessionId (เซสชัน); AssignSessionID (เซสชัน, SID); redismanager.set (serializationutils.serialize (session.getId (). toString ()), serializationutils.serialize (เซสชัน)); redismanager.expire (serializationutils.serialize (session.getid (). toString ()), 60); กลับซิด; } @Override เซสชันที่ได้รับการป้องกัน doreadsession (serializable serializable) {// วิธีนี้จริง ๆ แล้วจะอ่านเซสชันผ่าน SessionID ทุกครั้งที่คุณอ่านเวลาความล้มเหลวจะต้องรีเซ็ตไบต์ [] aa = redismanager.get (serializationutils.serialize (serializable.toString ())); เซสชันเซสชัน = (เซสชัน) serializationutils.deserialize (aa); redismanager.set (serializationutils.serialize (serializable.toString ()), serializationutils.serialize (เซสชัน)); redismanager.expire (serializationutils.serialize (serializable.toString ()), 60); เซสชั่นกลับ; -4) ขั้นตอนต่อไปคือการรับเซสชันของ Shiro ในตรรกะหลังจากเข้าสู่ระบบที่ประสบความสำเร็จแล้วตั้งค่าข้อมูลผู้ใช้ใน
แพ็คเกจ com.smart.controller; นำเข้า com.smart.pojo.user; นำเข้า com.smart.service.userservice; นำเข้า org.apache.shiro.securityutils; นำเข้า org.apache.shiro.mgt.securitymanager; org.slf4j.loggerfactory; นำเข้า org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.steretype.controller; นำเข้า org.springframework.ui.model; javax.servlet.http.httpservletRequest; นำเข้า Javax.servlet.http.httpservletResponse;@controller@requestmapping ("/user") คลาสสาธารณะ usercontroller {@autowired ผู้ใช้ส่วนตัวผู้ใช้บริการ; @autowired Private SecurityManager SM; // Inject SecurityManager Logger ส่วนตัว = loggerFactory.getLogger (userController.class); @RequestMapping (value = "/loginPage") สตริงสาธารณะ loginPage () {return "user/userlogin"; } @RequestMapping (value = "/userlogin", method = requestMethod.post) สตริงสาธารณะ userlogin (@requestparam (value = "name") ชื่อสตริง, @requestparam (value = "pwd") สตริง pwd, โมเดลโมเดล) {logger.info ("ป้อน userlogin ... "); user user = userservice.getUserByNameAndPassword (ชื่อ, PWD); if (user == null) {logger.info ("ผู้ใช้ไม่มีอยู่ ... "); Model.AdDattribute ("LOGIN_ERROR", "ข้อผิดพลาดชื่อผู้ใช้หรือรหัสผ่าน"); ส่งคืน "user/userlogin"; } SecurityUtils.SetSecurityManager (SM); หัวเรื่อง CurrentUser = SecurityUts.getSubject (); currentUser.getSession (). setAttribute ("login_user", ผู้ใช้); กลับ "เปลี่ยนเส้นทาง:/พนักงาน/รายการ"; -รับผู้ใช้ปัจจุบันใน Shiro มันเป็นธีมจากนั้นรับเซสชันที่สอดคล้องกันและตั้งค่าข้อมูลผู้ใช้ในนั้น มันรู้สึกเหมือนการทำงานของเซสชัน HTTP หรือไม่? ฮ่าฮ่า.
5) ในที่สุดกำหนดตัวดักจับ SpringMVC เพื่อรับข้อมูลผู้ใช้ในเซสชันที่สอดคล้องกันใน interceptor หากไม่สามารถรับได้มันจะข้ามไปยังอินเตอร์เฟสเข้าสู่ระบบ
แพ็คเกจ com.smart.core.shiro; นำเข้า com.smart.pojo.user; นำเข้า org.apache.shiro.securityutils; นำเข้า org.apache.shiro.mgt.securityManager นำเข้า org.apache.shiro.subject.subject; org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.web.servlet.handlerinterceptor; นำเข้า org.springframework.web.servlet.modelandview; นำเข้า Javax.servlet.htt javax.servlet.http.httpservletResponse; คลาสสาธารณะ LoginInterceptor ใช้ HandlerInterceptor {Logger ส่วนตัว logger = loggerFactory.getLogger (loginInterceptor.class); @autowired Private SecurityManager SM; @Override บูลีนสาธารณะ prehandle (httpservletrequest httpservletrequest, httpservletResponse httpservletResponse, วัตถุ o) โยนข้อยกเว้น {logger.info ("ป้อน loginInterceptor ... "); httpservletRequest Request = httpservletRequest; httpservletResponse response = httpservletResponse; logger.info ("ขอ uri ===>"+request.getRequesturi ()); // หากเป็นคำขอสำหรับหน้าเข้าสู่ระบบมันจะไม่ถูกดักจับมิฉะนั้นมันจะตกอยู่ในลูปตายถ้า (request.getRequesturi (). มี ("LoginPage") || request.getRequesturi () มี ("userlogin")) {กลับมาจริง; } else {SecurityUtils.SetSecurityManager (SM); หัวเรื่อง CurrentUser = SecurityUts.getSubject (); Object OBJ = CurrentUser.getSession (). GetAttribute ("LOGIN_USER"); if (obj == null) {response.sendredirect ("http: // localhost: 8080/user/loginpage"); กลับเท็จ; } else {user user = (ผู้ใช้) obj; if (user == null || user.getName () == null) {response.sendredirect ("http: // localhost: 8080/user/loginpage"); กลับเท็จ; } else {return true; }}}} @Override โมฆะสาธารณะ Postthandle (httpservletrequest httpservletrequest, httpservletResponse httpservletResponse, Object O, ModelandView ModelandView) httpservletResponse, Object O, Exception E) โยนข้อยกเว้น {}}มันอยู่ตรงนี้ หากคุณเข้าถึงข้อมูลหน้าแรกโดยตรงตอนนี้จะข้ามไปยังหน้าเข้าสู่ระบบโดยอัตโนมัติ
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com