Keycloak מוטבע ביישום אתחול האביב

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

Keycloak הוא פתרון קוד פתוח לניהול זהויות וגישה מנוהל על ידי RedHat, ופותח בג'אווה על ידי JBoss.

במדריך זה נלמד כיצד להקים שרת Keycloak המוטבע ביישום Spring Boot. זה מקל על הפעלת שרת Keycloak שהוגדר מראש.

ניתן להפעיל את Keycloak גם כשרת עצמאי, אך אז זה כרוך בהורדה והתקנה דרך מסוף הניהול.

2. תצורה מקדימה של מפתחות

ראשית, בואו נבין כיצד נוכל להגדיר מראש שרת Keycloak.

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

כל מה שניתן להגדיר באמצעות מסוף הניהול של Keycloak נמשך ב- JSON זה.

שרת ההרשאה שלנו יוגדר מראש עם baeldung-realm.json. בואו נראה כמה תצורות רלוונטיות בקובץ:

  • משתמשים: משתמשי ברירת המחדל שלנו יהיו [מוגן בדוא"ל] ו [מוגן בדוא"ל]; יהיה להם גם את האישורים שלהם כאן
  • לקוחות: נגדיר לקוח עם המזהה לקוח חדש
  • standardFlowEnabled: מוגדר כ- true להפעלת זרימת קוד ההרשאה עבור לקוח חדש
  • redirectUris: לקוח חדשכתובות ה- URL שהשרת ינתב אליהן לאחר אימות מוצלח מפורטות כאן
  • webOrigins: מכוון ל “+” כדי לאפשר תמיכה ב- CORS בכל כתובות האתרים הרשומות כ- redirectUris

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

3. תצורת Maven

מכיוון שנטמיע את Keycloak בתוך יישום Spring Boot, אין צורך להוריד אותו בנפרד.

במקום זאת, נגדיר את מערך התלות הבא:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-starter-data-jpa com.h2database h2 runtime 

שים לב שאנחנו משתמשים בגרסת 2.2.6.RELEASE של Spring Boot כאן. התלות spring-boot-starter-data-jpa ו- H2 נוספו להתמדה. האחר springframework.boot התלות הן לתמיכה באינטרנט, מכיוון שאנו צריכים להיות מסוגלים להריץ את שרת ההרשאה של Keycloak וכן את קונסולת הניהול כשירותי אינטרנט.

נצטרך גם כמה תלות עבור Keycloak ו- RESTEasy:

 org.jboss.resteasy resteasy-jackson2-provider 3.12.1 סופי org.keycloak keycloak-dependencies-server-all 11.0.2 pom 

בדוק באתר Maven לגבי הגרסאות האחרונות של Keycloak ו- RESTEasy.

ולבסוף, עלינו לבטל את ה כדי להשתמש בגרסה שהוכרזה על ידי Keycloak במקום זו שהוגדרה על ידי Spring Boot:

 10.1.8 גמר 

4. תצורה משובצת של מפתחות

בואו נגדיר את תצורת האביב עבור שרת ההרשאה שלנו:

@Configuration public class EmbeddedKeycloakConfig {@Bean ServletRegistrationBean keycloakJaxRsApplication (KeycloakServerProperties keycloakServerProperties, DataSource dataSource) זורק חריג {mockJndiEnvironment (dataSource); EmbeddedKeycloakApplication.keycloakServerProperties = keycloakServerProperties; ServletRegistrationBean servlet = ServletRegistrationBean חדש (HttpServlet30Dispatcher חדש ()); servlet.addInitParameter ("javax.ws.rs.Application", EmbeddedKeycloakApplication.class.getName ()); servlet.addInitParameter (ResteasyContextParameters.RESTEASY_SERVLET_MAPPING_PREFIX, keycloakServerProperties.getContextPath ()); servlet.addInitParameter (ResteasyContextParameters.RESTEASY_USE_CONTAINER_FORM_PARAMS, "נכון"); servlet.addUrlMappings (keycloakServerProperties.getContextPath () + "/ *"); servlet.setLoadOnStartup (1); servlet.setAsyncSupported (true); החזרת סרוולט; } @Bean FilterRegistrationBean keycloakSessionManagement (KeycloakServerProperties keycloakServerProperties) {FilterRegistrationBean filter = new FilterRegistrationBean (); filter.setName ("ניהול מושב Keycloak"); filter.setFilter (EmbeddedKeycloakRequestFilter חדש ()); filter.addUrlPatterns (keycloakServerProperties.getContextPath () + "/ *"); מסנן החזרה; } mockJndiEnvironment ריק (DataSource dataSource) זורק NamingException {NamingManager.setInitialContextFactoryBuilder ((env) -> (סביבה) -> InitialContext חדש () {@Override חיפוש אובייקט ציבורי (שם שם) {חיפוש חוזר (name.toString)); } @Override חפץ אובייקט ציבורי (שם מחרוזת) {if ("spring / datasource" .equals (name)) {return dataSource;} return null;} @Override NameParser public getNameParser (שם מחרוזת) {return CompositeName :: new;} @ ביטול ציבורי ריק () {}}); }} 

הערה: אל תדאגו לגבי שגיאת האוסף, נגדיר את ה- EmbeddedKeycloakRequestFilter כיתה בהמשך.

כפי שניתן לראות כאן, הגדרנו לראשונה את Keycloak כיישום JAX-RS עם KeycloakServerProperties לאחסון מתמשך של מאפייני Keycloak כמפורט בקובץ הגדרת התחום שלנו. לאחר מכן הוספנו פילטר לניהול הפעלות ולעגנו לסביבת JNDI לשימוש ב- קפיץ / מקור נתונים, שהוא מסד הנתונים H2 בזיכרון שלנו.

5. KeycloakServerProperties

עכשיו בואו נסתכל על ה- KeycloakServerProperties הרגע הזכרנו:

@ConfigurationProperties (קידומת = "keycloak.server") מחלקה ציבורית KeycloakServerProperties {String contextPath = "/ auth"; מחרוזת realmImportFile = "baeldung-realm.json"; AdminUser adminUser = AdminUser חדש (); // getters and setters class static public AdminUser {String username = "admin"; סיסמת מחרוזת = "admin"; // גטרים וקובעים}} 

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

6. EmbeddedKeycloakApplication

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

מחלקה ציבורית EmbeddedKeycloakApplication מרחיב את KeycloakApplication {פרטית סטטית סופית לוגר LOG = LoggerFactory.getLogger (EmbeddedKeycloakApplication.class); סטטי KeycloakServerProperties keycloakServerProperties; בטל ריק מוגן loadConfig () {JsonConfigProviderFactory מפעל = חדש RegularJsonConfigProviderFactory (); Config.init (factory.create () .orElseThrow (() -> NoSuchElementException חדש ("אין ערך קיים"))); } ציבורי EmbeddedKeycloakApplication () {createMasterRealmAdminUser (); createBaeldungRealm (); } ריק ריק createMasterRealmAdminUser () {KeycloakSession session = getSessionFactory (). create (); ApplianceBootstrap applianceBootstrap = ApplianceBootstrap חדש (הפעלה); AdminUser admin = keycloakServerProperties.getAdminUser (); נסה את {session.getTransactionManager (). התחל (); applianceBootstrap.createMasterRealmUser (admin.getUsername (), admin.getPassword ()); session.getTransactionManager (). commit (); } לתפוס (Exception ex) {LOG.warn ("לא ניתן ליצור משתמש מנהל מערכת keycloak: {}", ex.getMessage ()); session.getTransactionManager (). החזרה (); } session.close (); } ריק ריק createBaeldungRealm () {מושב KeycloakSession = getSessionFactory (). create (); נסה את {session.getTransactionManager (). התחל (); מנהל RealmManager = RealmManager חדש (הפעלה); Resource lessonRealmImportFile = ClassPathResource חדש (keycloakServerProperties.getRealmImportFile ()); manager.importRealm (JsonSerialization.readValue (lessonRealmImportFile.getInputStream (), RealmRepresentation.class)); session.getTransactionManager (). commit (); } catch (Exception ex) {LOG.warn ("נכשל ייבוא ​​קובץ json Realm: {}", ex.getMessage ()); session.getTransactionManager (). החזרה (); } session.close (); }} 

7. יישומי פלטפורמה בהתאמה אישית

כפי שאמרנו, Keycloak פותחה על ידי RedHat / JBoss. לכן, הוא מספק ספריות פונקציונליות והרחבות לפריסת היישום בשרת Wildfly, או כפתרון Quarkus.

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

לדוגמא, ב EmbeddedKeycloakApplication הגדרנו זה עתה טעינו לראשונה את תצורת השרת של Keycloak keycloak-server.json, באמצעות תת-מחלקה ריקה של התקציר JsonConfigProviderFactory:

מחלקה ציבורית RegularJsonConfigProviderFactory מרחיב את JsonConfigProviderFactory {}

ואז, הרחבנו יישום Keycloak ליצור שני תחומים: לִשְׁלוֹט ו ביילדונג. אלה נוצרים בהתאם למאפיינים שצוינו בקובץ הגדרת התחום שלנו, baeldung-realm.json.

כפי שאתה יכול לראות, אנו משתמשים ב- KeycloakSession כדי לבצע את כל העסקאות, וכדי שזה יעבוד כמו שצריך, היינו צריכים ליצור מותאם אישית AbstractRequestFilter (EmbeddedKeycloakRequestFilter) והגדר שעועית לכך באמצעות a KeycloakSessionServletFilter בתוך ה EmbeddedKeycloakConfig קוֹבֶץ.

בנוסף, אנו זקוקים לכמה ספקים מותאמים אישית כך שיהיה לנו יישומים משלנו org.keycloak.common.util.ResteasyProvider ו org.keycloak.platform.PlatformProvider ולא להסתמך על תלות חיצונית.

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

8. להביא את הכל ביחד

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

כדי לקרב את הכל, עלינו להגדיר את התצורה של Spring ו- Application Boot Boot.

8.1. application.yml

נשתמש ב- YAML פשוט לתצורות האביב:

שרת: יציאה: 8083 קפיץ: מקור נתונים: שם משתמש: sa url: jdbc: h2: mem: testdb keycloak: server: context נתיב: / auth admin משתמש: שם משתמש: סיסמת bael-admin: ******** realmImportFile: baeldung- realm.json

8.2. יישום אתחול האביב

לבסוף, הנה יישום אתחול האביב:

@SpringBootApplication (exclude = LiquibaseAutoConfiguration.class) @EnableConfigurationProperties (KeycloakServerProperties.class) public class AuthorizationServerApp {private static final Logger LOG = LoggerFactory.getLogger (AuthorizationServerApp.class); ראשי ריק סטטי ציבורי (String [] args) זורק Exception {SpringApplication.run (AuthorizationServerApp.class, args); } @Bean ApplicationListener onApplicationReadyEventListener (ServerProperties serverProperties, KeycloakServerProperties keycloakServerProperties) {return (evt) -> {Integer port = serverProperties.getPort (); מחרוזת keycloakContextPath = keycloakServerProperties.getContextPath (); LOG.info ("Keycloak מוטבע התחיל: // localhost: {} {} לשימוש keycloak", port, keycloakContextPath); }; }}

יש לציין שכאן אפשרנו את KeycloakServerProperties תצורה כדי להזרים אותו לתוך יישום מאזין אפונה.

לאחר הפעלת השיעור הזה, אנו יכולים לגשת לדף הפתיחה של שרת ההרשאה בכתובת // localhost: 8083 / auth /.

9. מסקנה

במדריך מהיר זה, ראינו כיצד להתקין שרת Keycloak המוטמע ביישום Spring Boot. קוד המקור ליישום זה זמין ב- GitHub.

הרעיון המקורי ליישום זה פותח על ידי תומאס דרימונט וניתן למצוא אותו בפרויקט embedded-spring-boot-keycloak-server.