使用 Keycloak 輕鬆保護您的 Spring Boot 應用程式

2017 年 5 月 29 日,作者:Sébastien Blanc

什麼是 Keycloak?

雖然安全性是任何應用程式的關鍵面向,但其執行可能很困難。更糟的是,它經常被忽略、執行不佳且侵入程式碼。但最近出現了一些安全性伺服器,可允許外包和委派所有驗證和授權方面。在這些伺服器中,最有前途的伺服器之一是 Keycloak,它是開放原始碼、彈性且與任何技術無關的伺服器,可以輕鬆部署/調整在其自己的基礎架構中。此外,Keycloak 不僅僅是一個驗證伺服器,它還提供完整的身分管理系統、用於 LDAP 等第三方的使用者聯合,以及更多功能...請在這裡查看。該專案也可以在 Github 上找到

Spring Boot 和 Keycloak

Keycloak 為需要與 Keycloak 執行個體互動的應用程式提供轉接器。有適用於 WildFly/EAP、NodeJS、Javascript 以及當然適用於 Spring Boot 的轉接器。

設定 Keycloak 伺服器


您有不同的選項可以設定 Keycloak 伺服器,但最簡單的方法可能是抓取獨立發行版、解壓縮它,然後就完成了!開啟終端機並前往您解壓縮的 Keycloak 伺服器,然後從 bin 目錄簡單地執行
./standalone.sh(bat)
然後開啟瀏覽器並前往 https://127.0.0.1:8080/auth。由於這是伺服器第一次執行,您必須建立一個管理使用者,所以讓我們建立一個使用者名稱為 admin、密碼為 admin 的管理使用者

 

現在您可以登入您的管理主控台並開始設定 Keycloak。

建立新的 Realm


Keycloak 定義了 Realm 的概念,您將在其中定義您的用戶端,在 Keycloak 術語中,這表示將由 Keycloak 保護的應用程式,它可以是 Web 應用程式、Java EE 後端、Spring Boot 等。所以讓我們透過簡單地按一下「新增 Realm」按鈕來建立一個新的 Realm

 

讓我們將其命名為「SpringBoot」。

建立用戶端、角色和使用者


現在我們需要定義一個用戶端,它將是我們的 Spring Boot 應用程式。前往「用戶端」區段,然後按一下「建立」按鈕。我們將我們的用戶端命名為「product-app」

 

在下一個畫面中,我們可以保留預設設定,但只需要輸入有效的重新導向 URL,Keycloak 將在使用者通過驗證後使用該 URL。將值設定為:「https://127.0.0.1:8081/*」

 

別忘了儲存!現在,我們將定義一個將分配給我們使用者的角色,讓我們建立一個名為「user」的簡單角色

 

最後,但同樣重要的是,讓我們建立一個使用者,只需要使用者名稱屬性,讓我們稱他為「testuser」

 

最後,我們需要設定他的認證資訊,因此前往您的使用者的認證資訊標籤並選擇一個密碼,我將在本文的其餘部分使用「password」,請務必關閉「暫時」旗標,除非您希望使用者在第一次驗證時必須變更密碼。現在前往「角色對應」標籤並分配角色「user」

 

我們現在已經完成了 Keycloak 伺服器的設定,我們可以開始建置我們的 Spring Boot 應用程式了!

建立簡單的應用程式


讓我們建立一個簡單的 Spring Boot 應用程式,您可能想要使用 Spring Initializr 並選擇以下選項
將您的應用程式命名為「product-app」並下載產生的專案

 

將應用程式匯入您最愛的 IDE,我將使用 IntelliJ。我們的應用程式將很簡單,並且只包含 2 個頁面
讓我們從在「/src/resources/static」中建立簡單的 index.html 檔案開始

<html>
<head>
    <title>My awesome landing page</title>
</head>
 <body>
   <h2>Landing page</h2>
   <a href="/products">My products</a>
 </body>
</html>


現在我們需要一個控制器

@Controller
class ProductController {

   @Autowired ProductService productService;

   @GetMapping(path = "/products")
   public String getProducts(Model model){
      model.addAttribute("products", productService.getProducts());
      return "products";
   }

   @GetMapping(path = "/logout")
   public String logout(HttpServletRequest request) throws ServletException {
      request.logout();
      return "/";
   }
}
如您所見,它很簡單;我們為產品頁面定義一個對應,為登出動作定義一個對應。您還會注意到我們正在呼叫一個「ProductService」,它將傳回一個字串清單,這些字串將放入我們的 Spring MVC Model 物件中,所以讓我們建立該服務
@Component
class ProductService {
   public List<String> getProducts() {
      return Arrays.asList("iPad","iPod","iPhone");
   }
}
我們也需要建立 product.ftl 範本,在「src/resources/templates」中建立此檔案

<#import "/spring.ftl" as spring>
<html>
<h2>My products</h2>
<ul>
<#list products as product>
    <li>$amp{product}</li>
</#list>
</ul>
<p>
    <a href="/logout">Logout</a>
</p>
</html>
在這裡,我們只是簡單地疊代我們的 Spring MVC Model 物件中的產品清單,並新增一個從應用程式登出的連結。剩下的就是將一些 keycloak 屬性新增到我們的 application.properties 中。

定義 Keycloak 的組態


有些屬性是必要的

keycloak.auth-server-url=https://127.0.0.1:8080/auth
keycloak.realm=springboot
keycloak.public-client=true
keycloak.resource=product-app
然後我們需要定義一些安全性限制,就像您在 web.xml 中使用 Java EE 應用程式一樣
keycloak.security-constraints[0].authRoles[0]=user
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/products/*
在這裡,我們只是簡單地定義對 /products/* 的每個請求都應該由經過驗證的使用者執行,而且此使用者應該具有角色「user」。最後一個屬性是確保我們的應用程式將在連接埠 8081 上執行

server.port=8081
我們都設定好了,我們可以執行我們的應用程式了!您有幾個選項可以執行您的 Spring Boot 應用程式,使用 Maven,您可以簡單地執行

mvn clean spring-boot:run
現在瀏覽到「https://127.0.0.1:8080」,您應該會看到登陸頁面,按一下「產品」連結,您將被重新導向到 Keycloak 登入頁面

 

使用我們的使用者「testuser/password」登入,您應該會被重新導向回您的產品頁面

 

恭喜!您已使用 Keycloak 保護了您的第一個 Spring Boot 應用程式。現在登出並返回 Keycloak 管理主控台,了解如何「調整」您的登入頁面。例如,您可以啟動「記住我」、「使用者註冊」,按一下「儲存」按鈕,然後返回您的登入畫面,您會看到已新增這些功能。

導入 Spring Security 支援


如果您是 Spring 使用者並且一直在研究安全性,則很可能您一直在使用 Spring Security。好吧,我有一些好消息:我們也有 Keycloak Spring Security 轉接器,它已經包含在我們的 Spring Boot Keycloak Starter 中。讓我們看看如何將 Spring Security 與 Keycloak 一起使用。

新增 Spring Security Starter


首先,我們需要 Spring Security 程式庫,最簡單的方法是在您的 pom.xml 中新增 spring-boot-starter-security 成品

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>

建立 SecurityConfig 類別


與任何使用 Spring Security 保護的專案一樣,需要一個擴充 WebSecurityConfigurerAdapter 的組態類別。Keycloak 提供其自己的子類別,您可以再次對其進行子類別化

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
 class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
   /**
    * Registers the KeycloakAuthenticationProvider with the authentication manager.
    */
   @Autowired
   public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
      keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
      auth.authenticationProvider(keycloakAuthenticationProvider);
   }

   @Bean
   public KeycloakConfigResolver KeycloakConfigResolver() {
      return new KeycloakSpringBootConfigResolver();
   }

   /**
    * Defines the session authentication strategy.
    */
   @Bean
   @Override
   protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
      return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
   }

   @Override
   protected void configure(HttpSecurity http) throws Exception
   {
      super.configure(http);
      http
            .authorizeRequests()
            .antMatchers("/products*").hasRole("user")
            .anyRequest().permitAll();
   }
}
讓我們仔細看看最重要的幾個方法
現在我們可以移除先前在我們的 application.properties 檔案中定義的安全性限制,並新增另一個屬性,以將 Principal 名稱對應到我們的 Keycloak 使用者名稱
keycloak.principal-attribute=preferred_username
現在我們甚至可以在我們的控制器方法中注入 principal,並將使用者名稱放入 Spring MVC 模型中

@GetMapping(path = "/products")
public String getProducts(Principal principal, Model model){
   model.addAttribute("principal",principal);
   model.addAttribute("products", productService.getProducts());
   return "products";
}
最後,我們更新 product.ftl 範本以列印出使用者名稱

<#import "/spring.ftl" as spring>
<html>
<h2>Hello $amp{principal.getName()}</h2>
<ul>
<#list products as product>
    <li>$amp{product}</li>
</#list>
</ul>
<p>
    <a href="/logout">Logout</a>
</p>
</html>
重新啟動您的應用程式,再次驗證,它應該仍然可以運作,而且您也應該能夠在產品頁面上看到列印的使用者名稱
   

結論


我們在本文中了解了如何部署和組態 Keycloak 伺服器,然後保護 Spring Boot 應用程式,首先是使用 Java EE 安全性限制,然後是整合 Spring Security。在下一篇文章中,我們將分解此單體應用程式,這將使我們有機會

螢幕錄影

本文也提供「螢幕錄影」格式

資源