2021年6月22日火曜日

Spring Boot と Keycloak でアクセス制御したい

やっていく。

Path 権限
/ ログインしている人なら誰でもログイン可能
/users/user1 user1 のみログイン可能
/users/user2 user2 のみログイン可能
  • / に、各ユーザー用ページへのリンクを表示
  • ログインできないユーザーのページリンクがあっても無駄なので、 自分のページリンクのみを表示したい

前提

構築イメージ

+----------+
| Keycloak |
+----------+
 ↑ localhost:8080
+-----------------------+
| SpringBootApplication |
+-----------------------+
 ↑ localhost:8081
+---------+
| Browser |
+---------+

OAuth クライアントの追加

  1. http://localhost:8080 へアクセスし、 admin でログイン
  2. Clients -> Create ボタン押下
  3. Add Client ページが表示されるので、必要事項を記入して Save ボタン押下
    • Client ID : spring-boot
    • Client Protocol : openid-connect
    • Root URL : http://localhost:8081
  4. spring-boot の設定ページが表示されるため、必要な項目を更新して Save ボタン押下

Spring Boot アプリケーション作成

プロジェクトのひな形作成

Spring Initializr でプロジェクトのひな形を作成する。

今回使うのは こちら

Keycloak の依存を追加

Securing Applications and Services Guide に従い、 keycloak-spring-boot-starterkeycloak-adapter-bom を追加する。

最終的な pom.xml は以下。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>dev.mikoto2000.study.springboot.keycloak</groupId>
    <artifactId>gettingstarted</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gettingstarted</name>
    <description>Demo project for Spring Boot with Keycloak</description>
    <properties>
        <java.version>11</java.version>
    </properties>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties の修正

# server port
server.port=8081

# Keycloak
keycloak.auth-server-url=http://localhost:8080/auth

# レルム名を設定する。
keycloak.realm=MyApp

# クライアントIDを設定する。
keycloak.resource=spring-boot
keycloak.public-client=true

# OpenID ConnectのIDトークン属性を設定。
keycloak.principal-attribute=preferred_username

# ディレクトリと、アクセス許可のロールを定義
keycloak.security-constraints[0].authRoles[0]=authorized
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/
keycloak.security-constraints[1].authRoles[0]=user1
keycloak.security-constraints[1].securityCollections[0].patterns[0]=/users/user1
keycloak.security-constraints[2].authRoles[0]=user2
keycloak.security-constraints[2].securityCollections[0].patterns[0]=/users/user2

アプリケーション実装

コントローラーとテンプレートを作る。

コントローラー

package dev.mikoto2000.study.springboot.keycloak.gettingstarted;

import java.security.Principal;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * AppController
 */
@Controller
public class AppController {
    @GetMapping(path = "/")
    public String index(Principal principal, Model model) {
        model.addAttribute("username", principal.getName());

        return "index";
    }

    @GetMapping(path = "/users/{name}")
    public String customers(@PathVariable("name") String name, Principal principal, Model model) {

        model.addAttribute("username", name);
        return "userpage";
    }
}

テンプレート

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>index</title>
</head>
<body>
    <p th:text="'Hello, ' + ${username}"></p>

    <ul>
        <li><a th:href="'./users/' + ${username}" th:text="'./users/' + ${username}"></a></li>
    </ul>
</body>
</html>

userpage.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title th:text="${username} + '\'s page'"></title>
</head>
<body>
    <p th:text="'Hello, ' + ${username} + '!'"></p>
</body>
</html>

動作確認

.\mvnw.cmd spring-boot:run して http://localhost:8081 へアクセス。

user1user2 でログインして、別ユーザーのユーザーページが見れないことを確認。

今回の方法だと、存在しないユーザーが分かってしまうが今はとりあえずいいや…。

後は、ログアウトとかエラーページの整備もやらないとですね。

参考資料

0 件のコメント:

コメントを投稿