מבוא לאפאצ'י שירו

1. סקירה כללית

במאמר זה נבחן את אפאצ'י שירו, מסגרת אבטחה רב-תכליתית של Java.

המסגרת ניתנת להתאמה אישית ומודולרית, מכיוון שהיא מציעה אימות, הרשאה, הצפנה וניהול הפעלות.

2. תלות

לאפאצ'י שירו ​​יש הרבה מודולים. עם זאת, במדריך זה אנו משתמשים ב- שירו-ליבה חפץ בלבד.

בואו נוסיף אותו לשלנו pom.xml:

 org.apache.shiro shiro-core 1.4.0 

את הגרסה האחרונה של מודולי אפאצ'י שירו ​​ניתן למצוא ב- Maven Central.

3. קביעת תצורה של מנהל האבטחה

ה מנהל אבטחה הוא החלק המרכזי של המסגרת של אפאצ'י שירו. לרוב יישומים יפעלו מופע יחיד.

במדריך זה אנו חוקרים את המסגרת בסביבת שולחן עבודה. כדי להגדיר את המסגרת, עלינו ליצור shiro.ini קובץ בתיקיית המשאבים עם התוכן הבא:

[משתמשים] משתמש = סיסמה, מנהל משתמש 2 = סיסמה 2, עורך משתמש 3 = סיסמה 3, מחבר [תפקידים] מנהל = * עורך = מאמרים: * מחבר = מאמרים: לכתוב, מאמרים: שמור

ה [משתמשים] החלק של shiro.ini קובץ התצורה מגדיר את אישורי המשתמש המוכרים על ידי מנהל אבטחה. הפורמט הוא: עמ 'מנהל (שם משתמש) = סיסמה, תפקיד 1, תפקיד 2, ..., תפקיד.

התפקידים וההיתרים הקשורים אליהם מוצהרים ב [תפקידים] סָעִיף. ה מנהל לתפקיד ניתנת הרשאה וגישה לכל חלק ביישום. זה מצוין על ידי תו כללי (*) סֵמֶל.

ה עוֹרֵך לתפקיד כל ההרשאות הקשורות מאמרים בזמן ש מְחַבֵּר תפקיד יכול בלבד לְהַלחִין ו לשמור מאמר.

ה מנהל אבטחה משמש להגדרת תצורה של אבטחה מעמד. מ ה אבטחה אנו יכולים להשיג את המשתמש הנוכחי באינטראקציה עם המערכת ולבצע פעולות אימות והרשאה.

בואו נשתמש ב- IniRealm כדי לטעון את הגדרות המשתמש והתפקיד שלנו מה- shiro.ini ולאחר מכן השתמש בו כדי להגדיר את התצורה DefaultSecurityManager לְהִתְנַגֵד:

IniRealm iniRealm = IniRealm חדש ("מסלול כיתה: shiro.ini"); SecurityManager securityManager = DefaultSecurityManager חדש (iniRealm); SecurityUtils.setSecurityManager (securityManager); נושא currentUser = SecurityUtils.getSubject ();

עכשיו שיש לנו מנהל אבטחה מודע לאישורי המשתמש ולתפקידים שהוגדרו ב- shiro.ini קובץ, בואו נמשיך לאימות משתמשים ולהרשאות.

4. אימות

במינוחים של אפאצ'י שירו, א נושא האם כל ישות מקיימת אינטראקציה עם המערכת. זה יכול להיות בן אדם, תסריט או לקוח REST.

יִעוּד SecurityUtils.getSubject () מחזיר מופע של הזרם נושא, זה ה משתמש נוכחי.

עכשיו שיש לנו את משתמש נוכחי אובייקט, אנו יכולים לבצע אימות בתעודות המסופקות:

if (! currentUser.isAuthenticated ()) {UsernamePasswordToken token = new UsernamePasswordToken ("user", "password"); token.setRememberMe (נכון); נסה את {currentUser.login (אסימון); } לתפוס (UnknownAccountException uae) {log.error ("שם המשתמש לא נמצא!", Uae); } לתפוס (IncorrectCredentialsException קרח) {log.error ("אישורים לא חוקיים!", קרח); } לתפוס (LockedAccountException lae) {log.error ("החשבון שלך נעול!", lae); } לתפוס (AuthenticationException ae) {log.error ("שגיאה לא צפויה!", ae); }}

ראשית, אנו בודקים אם המשתמש הנוכחי טרם אומת. לאחר מכן אנו יוצרים אסימון אימות עם מנהל המשתמש (שם משתמש) ותעודה (סיסמה).

לאחר מכן, אנו מנסים להתחבר באמצעות האסימון. אם האישורים המסופקים נכונים, הכל אמור ללכת בסדר.

ישנם חריגים שונים למקרים שונים. אפשר גם לשים חריג מותאם אישית שמתאים יותר לדרישת היישום. ניתן לעשות זאת על ידי סיווג משנה של ה- חריג חשבון מעמד.

5. אישור

אימות מנסה לאמת את זהות המשתמש בזמן שהאישור מנסה לשלוט בגישה למשאבים מסוימים במערכת.

נזכיר שאנו מקצים תפקיד אחד או יותר לכל משתמש שיצרנו ב- shiro.ini קוֹבֶץ. יתר על כן, בחלק התפקידים אנו מגדירים הרשאות או רמות גישה שונות עבור כל תפקיד.

בואו נראה כיצד נוכל להשתמש בזה ביישום שלנו כדי לאכוף את בקרת הגישה למשתמשים.

בתוך ה shiro.ini קובץ, אנו מעניקים למנהל גישה כוללת לכל חלקי המערכת.

לעורך יש גישה כוללת לכל משאב / פעולה בכל הנוגע מאמרים, ומחבר מוגבל רק להלחין ולשמור מאמרים רק.

בואו בברכה את המשתמש הנוכחי על סמך תפקיד:

אם (currentUser.hasRole ("admin")) {log.info ("Admin Admin"); } אחר אם (currentUser.hasRole ("עורך")) {log.info ("ברוך הבא, עורך!"); } אחר אם (currentUser.hasRole ("מחבר")) {log.info ("ברוך הבא, מחבר"); } אחר {log.info ("ברוך הבא, אורח"); }

עכשיו, בואו נראה מה מותר למשתמש הנוכחי לעשות במערכת:

אם (currentUser.isPermitted ("מאמרים: לכתוב")) {log.info ("אתה יכול לחבר מאמר"); } אחר {log.info ("אינך רשאי לחבר מאמר!"); } אם (currentUser.isPermitted ("מאמרים: שמור")) {log.info ("אתה יכול לשמור מאמרים"); } אחר {log.info ("אינך יכול לשמור מאמרים"); } אם (currentUser.isPermitted ("מאמרים: פרסם")) {log.info ("אתה יכול לפרסם מאמרים"); } אחר {log.info ("אינך יכול לפרסם מאמרים"); }

6. תצורת תחום

ביישומים אמיתיים, נצטרך דרך לקבל אישורי משתמש ממסד נתונים ולא מ- shiro.ini קוֹבֶץ. כאן נכנס לתמונה המושג Realm.

במינוח של אפאצ'י שירו, Realm הוא DAO המצביע על מאגר אישורי משתמש הדרושים לאימות והרשאה.

כדי ליצור ממלכה, אנחנו צריכים רק ליישם את תְחוּם מִמְשָׁק. זה יכול להיות מייגע; עם זאת, המסגרת מגיעה עם יישומי ברירת מחדל שמהם אנו יכולים לסווג משנה. אחת היישומים הללו היא JdbcRealm.

אנו יוצרים יישום ממלכתי מותאם אישית שמתארך JdbcRealm בכיתה ועוקף את השיטות הבאות: doGetAuthenticationInfo (), doGetAuthorizationInfo (), getRoleNamesForUser () ו getPermissions ().

בואו ניצור ממלכה על ידי סיווג משנה של ה- JdbcRealm מעמד:

מחלקה ציבורית MyCustomRealm מרחיב את JdbcRealm {// ...}

לשם הפשטות אנו משתמשים java.util.Map לדמות מסד נתונים:

אישורי מפה פרטיים = HashMap חדש (); מפה פרטית תפקידים = HashMap חדש (); מפה פרטית perm = HashMap חדש (); {credentials.put ("משתמש", "סיסמה"); credentials.put ("user2", "password2"); credentials.put ("user3", "password3"); role.put ("משתמש", HashSet חדש (Arrays.asList ("מנהל"))); role.put ("user2", HashSet חדש (Arrays.asList ("עורך"))); roller.put ("user3", HashSet חדש (Arrays.asList ("מחבר"))); perm.put ("admin", HashSet חדש (Arrays.asList ("*"))); perm.put ("עורך", HashSet חדש (Arrays.asList ("מאמרים: *"))); perm.put ("מחבר", HashSet חדש (Arrays.asList ("מאמרים: לחבר", "מאמרים: שמור"))); }

בואו נמשיך ונעקוף את doGetAuthenticationInfo ():

AuthenticationInfo מוגן doGetAuthenticationInfo (אסימון AuthenticationToken) זורק אסימון AuthenticationException {UsernamePasswordToken uToken = (UsernamePasswordToken); אם (uToken.getUsername () == null || uToken.getUsername (). isEmpty () ||! credentials.containsKey (uToken.getUsername ())) {זרוק UnknownAccountException חדש ("שם המשתמש לא נמצא!"); } להחזיר SimpleAuthenticationInfo חדש (uToken.getUsername (), credentials.get (uToken.getUsername ()), getName ()); }

הראשון ליהקנו את AuthenticationToken מסופק ל UsernamePasswordToken. מ ה uToken, אנו מחלצים את שם המשתמש (uToken.getUsername ()) והשתמש בו בכדי לקבל את אישורי המשתמש (סיסמה) ממסד הנתונים.

אם לא נמצא שום רשומה - אנחנו זורקים UnknownAccountException, אחרת אנו משתמשים בתעודה ובשם המשתמש כדי לבנות a SimpleAuthenticatioInfo אובייקט שהוחזר מהשיטה.

אם אישורי המשתמש חותכים עם מלח, עלינו להחזיר a SimpleAuthenticationInfo עם המלח המשויך:

להחזיר SimpleAuthenticationInfo חדש (uToken.getUsername (), credentials.get (uToken.getUsername ()), ByteSource.Util.bytes ("מלח"), getName ());

אנחנו גם צריכים לבטל את doGetAuthorizationInfo (), בנוסף ל getRoleNamesForUser () ו getPermissions ().

לבסוף, בואו נחבר את התחום המותאם אישית ל מנהל אבטחה. כל שעלינו לעשות הוא להחליף את ה- IniRealm למעלה עם התחום המותאם אישית שלנו, והעבירו אותו ל DefaultSecurityManagerבונה:

תחום ממלכה = MyCustomRealm חדש (); SecurityManager securityManager = DefaultSecurityManager חדש (תחום);

כל חלק אחר בקוד זהה לקודם. זה כל מה שאנחנו צריכים כדי להגדיר את מנהל אבטחה עם תחום מותאם אישית כראוי.

עכשיו השאלה היא - איך המסגרת תואמת את האישורים?

כברירת מחדל, ה- JdbcRealm משתמש ב- SimpleCredentialsMatcher, אשר רק בודק שוויון על ידי השוואת האישורים ב- AuthenticationToken וה AuthenticationInfo.

אם אנו חשים את הסיסמאות שלנו, עלינו ליידע את המסגרת לשימוש ב- HashedCredentialsMatcher במקום זאת. תצורות ה- INI לתחומים עם סיסמאות חשיש ניתן למצוא כאן.

7. התנתקות

כעת, לאחר שאמתנו את המשתמש, הגיע הזמן ליישם התנתקות. זה נעשה פשוט על ידי קריאה לשיטה אחת - שמבטלת את ביטול הפעלת המשתמש ומנתקת את המשתמש:

currentUser.logout ();

8. ניהול מושבים

המסגרת מגיעה באופן טבעי עם מערכת ניהול ההפעלות שלה. אם משתמשים בסביבת אינטרנט, ברירת המחדל היא ה- HttpSession יישום.

עבור יישום עצמאי, היא משתמשת במערכת ניהול הפעלות ארגוניות שלה. היתרון הוא שגם בסביבת שולחן עבודה תוכלו להשתמש באובייקט הפעלה כפי שהייתם עושים בסביבת אינטרנט טיפוסית.

בואו נסתכל על דוגמה מהירה ואינטראקציה עם ההפעלה של המשתמש הנוכחי:

מושב מושב = currentUser.getSession (); session.setAttribute ("מפתח", "ערך"); ערך מחרוזת = (מחרוזת) session.getAttribute ("מפתח"); if (value.equals ("value")) {log.info ("השיג את הערך הנכון! [" + value + "]"); }

9. שירו ​​ליישום אינטרנט עם אביב

עד כה התארנו את המבנה הבסיסי של אפאצ'י שירו ​​ויישמנו אותו בסביבת שולחן עבודה. בואו נמשיך בשילוב המסגרת ביישום Spring Boot.

שים לב שהמוקד העיקרי כאן הוא שירו, לא יישום האביב - אנחנו נשתמש בזה רק בכדי להפעיל יישום לדוגמה פשוט.

9.1. תלות

ראשית, עלינו להוסיף את תלות האב האביב של האביב pom.xml:

 org.springframework.boot spring-boot-starter-parent 2.2.6. שחרור 

לאחר מכן, עלינו להוסיף את התלות הבאות לאותו הדבר pom.xml קוֹבֶץ:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-freemarker org.apache.shiro shiro-spring-boot-web-starter $ {apache-shiro-core-version} 

9.2. תְצוּרָה

הוספת ה- shiro-spring-boot-web-starter תלות שלנו pom.xml יגדיר כברירת מחדל כמה תכונות של יישום Apache Shiro כגון מנהל אבטחה.

עם זאת, אנו עדיין צריכים להגדיר את תְחוּם ומסנני אבטחה של שירו. נשתמש באותו תחום מותאם אישית שהוגדר לעיל.

וכך, במחלקה הראשית בה פועל יישום Spring Boot, בואו נוסיף את הדברים הבאים אפונה הגדרות:

תחום הממלכה הציבורית של @Bean () {החזר MyCustomRealm חדש (); } @Bean הציבור ShiroFilterChainDefinition shiroFilterChainDefinition () {DefaultShiroFilterChainDefinition filter = new DefaultShiroFilterChainDefinition (); filter.addPathDefinition ("/ secure", "authc"); filter.addPathDefinition ("/ **", "אנון"); מסנן החזרה; }

בתוך ה הגדרת ShiroFilterChainDefinition, יישמנו את אימות לסנן ל /לבטח נתיב ויישם את אנון לסנן בנתיבים אחרים באמצעות דפוס הנמלים.

שניהם אימות ו אנון מסננים מגיעים כברירת מחדל ליישומי אינטרנט. ניתן למצוא כאן מסנני ברירת מחדל אחרים.

אם לא הגדרנו את תְחוּם אפונה, תצורת ShiroAutoConfiguration יספק, כברירת מחדל IniRealm יישום המצפה למצוא א shiro.ini קובץ src / main / resources אוֹ src / main / resources / META-INF.

אם אנחנו לא מגדירים א הגדרת ShiroFilterChainDefinition שעועית, המסגרת מאבטחת את כל הנתיבים ומגדירה את כתובת ה- URL כניסה login.jsp.

אנו יכולים לשנות את כתובת אתר הכניסה המוגדרת כברירת מחדל וברירות מחדל אחרות על ידי הוספת הערכים הבאים לכתובת שלנו application.properties:

shiro.loginUrl = / התחבר shiro.successUrl = / מאובטח shiro.unauthorizedUrl = / כניסה

עכשיו כשה- אימות מסנן הוחל על /לבטח, כל הבקשות למסלול זה ידרוש אימות טופס.

9.3. אימות והרשאה

בואו ניצור ShiroSpringController עם מיפוי הנתיבים הבא: /אינדקס, /בתחברות ו /לבטח.

ה התחברות() השיטה היא המקום בו אנו מיישמים אימות משתמש בפועל כמתואר לעיל. אם האימות הצליח, המשתמש ינותב לדף המאובטח:

נושא הנושא = SecurityUtils.getSubject (); if (! subject.isAuthenticated ()) {UsernamePasswordToken token = New UsernamePasswordToken (cred.getUsername (), cred.getPassword (), cred.isRememberMe ()); נסה את {subject.login (אסימון); } לתפוס (AuthenticationException ae) {ae.printStackTrace (); attr.addFlashAttribute ("שגיאה", "אישורים לא חוקיים"); להחזיר "redirect: / login"; }} להחזיר "redirect: / secure";

ועכשיו ב לבטח() יישום, משתמש נוכחי הושג על ידי הפעלת SecurityUtils.getSubject (). תפקידו והרשאותיו של המשתמש מועברים לדף המאובטח, כמו גם למנהל המשתמש:

נושא currentUser = SecurityUtils.getSubject (); תפקיד מחרוזת = "", הרשאה = ""; אם (currentUser.hasRole ("admin")) {role = role + "אתה מנהל מערכת"; } אחר אם (currentUser.hasRole ("עורך")) {role = role + "אתה עורך"; } אחרת אם (currentUser.hasRole ("מחבר")) {role = role + "אתה מחבר"; } אם (currentUser.isPermitted ("מאמרים: לכתוב")) {הרשאה = הרשאה + "אתה יכול לחבר מאמר,"; } אחר {הרשאה = הרשאה + "אינך רשאי להרכיב מאמר !,"; } אם (currentUser.isPermitted ("מאמרים: שמור")) {הרשאה = הרשאה + "אתה יכול לשמור מאמרים,"; } אחר {הרשאה = הרשאה + "\ n אינך יכול לשמור מאמרים,"; } אם (currentUser.isPermitted ("מאמרים: פרסם")) {הרשאה = הרשאה + "\ n אתה יכול לפרסם מאמרים"; } אחר {הרשאה = הרשאה + "\ n אינך יכול לפרסם מאמרים"; } modelMap.addAttribute ("שם משתמש", currentUser.getPrincipal ()); modelMap.addAttribute ("הרשאה", הרשאה); modelMap.addAttribute ("תפקיד", תפקיד); להחזיר "מאובטח";

וסיימנו. כך נוכל לשלב את אפאצ'י שירו ​​ביישום אתחול האביב.

כמו כן, שים לב כי המסגרת מציעה הערות נוספות בהן ניתן להשתמש לצד הגדרות שרשרת סינון כדי להבטיח את היישום שלנו.

10. שילוב JEE

שילוב של אפאצ'י שירו ​​ביישום JEE הוא רק עניין של הגדרת התוכנה web.xml קוֹבֶץ. כרגיל, התצורה מצפה shiro.ini להיות בדרך הכיתה. תצורת דוגמה מפורטת זמינה כאן. כמו כן, ניתן למצוא את תגי ה- JSP כאן.

11. מסקנה

במדריך זה בדקנו את מנגנוני האימות והאישור של אפאצ'י שירו. התמקדנו גם כיצד להגדיר תחום מותאם אישית ולחבר אותו ל מנהל אבטחה.

כמו תמיד, קוד המקור השלם זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found