Keycloak 入門實戰(4)--客戶端適配器使用


Keycloak 提供了客戶端適配器來方便各應用程序的接入,本文主要介紹在 Tomcat 和 SpringBoot 應用中如何使用 Keycloak 來保護資源;文中使用到的軟件版本:Java 1.8.0_191、Keycloak 1.16.1、Tomcat 8 .5.76、SpringBoot 2.5.9。

1、Keycloak 地址

這里假設 Keycloak 已安裝完成,地址為 http://10.49.196.10:8080/auth。Keycloak 的安裝方法可以參考:Keycloak 入門實戰(2)--安裝

2、Tomcat 中使用 Keycloak

2.1、下載 Tomcat 的適配器

https://www.keycloak.org/archive/downloads-16.1.1.html

2.2、安裝適配器

把下載的文件(keycloak-oidc-tomcat-adapter-16.1.1.tar.gz)解壓到 Tomcat 的 lib 目錄下。

2.3、設置 Keycloak Valve

在 web 應用的 META-INF 目錄下創建 context.xml 文件:

<Context>
    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
</Context>

2.4、生成 keycloak.json 文件

假設自己 web 應用的 context-path 為 /keycloak-tomcat,在 Keycloak 中創建一個客戶端:client-tomcat

在該客戶端的安裝 tab 頁,格式選 “Keycloak OIDC JSON”,點擊  “下載” 按鈕。

 把下載下來的 keycloak.json 文件拷貝到 web 應用的 WEB-INF 目錄下。

2.5、修改應用 web.xml 文件定義資源保護規則

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <security-constraint>
        <!--登出url不需要保護-->
        <web-resource-collection>
            <web-resource-name>logout</web-resource-name>
            <url-pattern>/logout.jsp</url-pattern>
        </web-resource-collection>
    </security-constraint>

    <security-constraint>
        <!--被保護的資源-->
        <web-resource-collection>
            <web-resource-name>admin</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
            <url-pattern>/system/*</url-pattern>
        </web-resource-collection>
        <!--可以訪問保護資源的角色,這里出現的角色需要在 security-role 中聲明-->
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <!--被保護的資源-->
        <web-resource-collection>
            <web-resource-name>user</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <!--可以訪問保護資源的角色,這里出現的角色需要在 security-role 中聲明-->
        <auth-constraint>
            <role-name>user</role-name>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <!--登錄方法-->
        <auth-method>KEYCLOAK</auth-method>
        <!--領域名稱,可為空-->
        <realm-name></realm-name>
    </login-config>

    <!--聲明角色-->
    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>

2.6、創建用戶及角色

在 Keycloak 中創建如下用戶和角色:

用戶 擁有角色
admin admin
test-user user

2.7、測試應用

把 web 應用部署到 Tomcat 中並訪問應用:http://localhost:8080/keycloak-tomcat,此時頁面會跳轉到 Keycloak 的登錄頁面:

 輸入用戶名密碼后會跳轉到自己應用的頁面。使用 admin 用戶登錄后,可以訪問應用的所有 url;如果使用 test-user 用戶登錄並訪問 http://localhost:8080/keycloak-tomcat/admin/index.jsp 會報 403 錯誤:

2.8、登出

這里為了方便使用一個 jsp(/logout.jsp) 來執行登出並跳到應用首頁:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
  request.logout();
  response.sendRedirect(request.getContextPath());
%>

訪問 http://localhost:8080/keycloak-tomcat/logout.jsp,由於登出后會跳到應用的首頁,首頁屬於被保護的資源,所以又會跳轉到 Keycloak 的登錄頁面。

Tomcat 整合 Keycloak 的詳細說明可參考官網:https://www.keycloak.org/docs/16.1/securing_apps/index.html#_spring_boot_adapter。

3、SpringBoot 中使用 Keycloak

3.1、引入依賴

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.keycloak.bom</groupId>
            <artifactId>keycloak-adapter-bom</artifactId>
            <version>16.1.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    ...
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-starter</artifactId>
    </dependency>
</dependencies>

3.2、創建客戶端

假設 SpringBoot 應用的 context-path 為 /,在 Keycloak 中創建客戶端:client-springboot

3.3、創建用戶及角色

在 Keycloak 中創建如下用戶和角色:

用戶 擁有角色
admin admin
test-user user

3.4、定義資源保護規則(application.yml)

keycloak:
  public-client: true
  auth-server-url: http://10.49.196.10:8080/auth
  realm: master
  resource: client-springboot
  security-constraints:
    -  #登出 url 不需要權限控制
      securityCollections:
        - name: logout
          patterns:
            - /logout
    - #管理員相關資源保護, admin 角色的用戶可以訪問
      authRoles:
        - admin
      securityCollections:
        -
          name: admin
          patterns:
            - /admin/*
            - /system/*
    - #用戶相關資源保護, user 或 admin 角色的用戶可以訪問
      authRoles:
        - admin
        - user
      securityCollections:
        -
          name: user
          patterns:
            - /*

3.5、編寫測試 Controller

package com.abc.demo.keycloak.controller;

import org.keycloak.KeycloakPrincipal;
import org.keycloak.representations.AccessToken;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.Principal;
import java.util.Set;

@RequestMapping("/*")
@RestController
public class TestController {
    @ResponseBody
    @RequestMapping("/")
    public String welcome() {
        return "welcome";
    }

    @ResponseBody
    @RequestMapping("/admin/index")
    public String adminIndex() {
        return "admin index";
    }

    @ResponseBody
    @RequestMapping("/user/index")
    public String userIndex() {
        return "user index";
    }

    /**
     * 獲取用戶信息
     * @param principal
     * @return
     */
    @ResponseBody
    @RequestMapping("/getUserInfo")
    public String getUserInfo(Principal principal) {
        String result = "";
        if (principal instanceof KeycloakPrincipal) {
            AccessToken accessToken = ((KeycloakPrincipal) principal).getKeycloakSecurityContext().getToken();
            String preferredUsername = accessToken.getPreferredUsername();
            AccessToken.Access realmAccess = accessToken.getRealmAccess();
            Set<String> roles = realmAccess.getRoles();
            result = "當前登錄用戶:" + preferredUsername + ", 角色:" + roles;
        }
        return result;
    }

    /**
     * 登出
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping("/logout")
    public void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.logout();
        response.sendRedirect(request.getContextPath());
    }
}

3.6、測試應用

訪問應用:http://localhost:8080,此時頁面會跳轉到 Keycloak 的登錄頁面:

 輸入用戶名密碼后會跳轉到自己應用的 url。使用 admin 用戶登錄后,可以訪問應用的所有 url;如果使用 test-user 用戶登錄並訪問 http://localhost:8080/admin/index 會報 403 錯誤:

3.7、登出

訪問登出 url:http://localhost:8080/logout,由於登出后會跳到應用的首頁,首頁屬於被保護的資源,所以又會跳轉到 Keycloak 的登錄頁面。

SpringBoot 整合 Keycloak 的詳細說明可參考官網:https://www.keycloak.org/docs/16.1/securing_apps/index.html#_spring_boot_adapter。

4、可能出現問題

4.1、Token is not active

在單點登錄的時候應用可能會報如下錯誤:

org.keycloak.adapters.OAuthRequestAuthenticator.resolveCode failed verification of token: Token is not active

這是由於 Keycloak 運行的機器和應用運行的機器時間相差較大導致的,處理方法:修改時間錯誤的機器上時間,使各機器上的時間一致。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM