使用 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)
然后打开浏览器,转到 http://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 将在用户身份验证后使用它。将其值设置为:“http://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=http://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
现在浏览到“http://127.0.0.1:8080”,您应该会看到登录页面,点击“产品”链接,您将被重定向到 Keycloak 登录页面。

 

使用我们的用户“testuser/password”登录,您应该会重新定向回产品页面。

 

恭喜!您已经使用 Keycloak 保护了您的第一个 Spring Boot 应用程序。现在注销,返回到 Keycloak 管理控制台,然后了解如何“调整”您的登录页面。例如,您可以激活“记住我”,“用户注册”,点击保存按钮,然后返回到登录屏幕,您将看到这些功能已添加。

介绍 Spring Security 支持


如果您是 Spring 用户,并且一直在尝试安全性,那么您很有可能一直在使用 Spring Security。好消息是:我们也有一个 Keycloak Spring Security 适配器,它已经包含在我们的 Spring Boot Keycloak 启动器中。让我们看看如何利用 Spring Security 与 Keycloak 结合使用。

添加 Spring Security 启动器


首先,我们需要 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 服务器,然后使用 Java EE 安全约束,然后通过集成 Spring Security 来保护 Spring Boot 应用程序。在下一篇文章中,我们将分解这个单体应用程序,这将使我们有机会

屏幕录制

本文也以“屏幕录制”格式提供。

资源