keycloak的使用

keycloak是开源的认证服务器,详细使用见官网:https://www.keycloak.org

安装

在开发时最方便的使用方式是在Docker下安装:

docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.0.2 start-dev

创建完成后,可以使用admin/admin登录http://localhost:8080进行下一步的操作。

可以先创建新的realm,类似于租户。然后在realm下创建用户、角色等。接下来创建client,然后用client连接认证服务器。

创建用户后,可以通过链接http://localhost:8080/realms/myrealm/account登录到账号,这里myrealm是用户所属realm。

使用脚本导入数据

安装完keycloak后,可以使用界面手工创建realm、用户和角色,也可以使用脚本导入数据。

创建一个node.js项目,引入下面的依赖项

  • “@keycloak/keycloak-admin-client”: “26.0.2”,
  • “keycloak-connect”: “26.0.2”
    然后编写脚本
    1
    2
    3
    4
    5
    6
    7
    8
    import KcAdminClient from '@keycloak/keycloak-admin-client';
    import config from '../config/config.js';

    const adminClient = new KcAdminClient(config.adminClient)

    await adminClient.auth(config.adminClient);

    export default adminClient;
    这个脚本创建管理员权限的客户端,配置项在config中定义:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const baseUrl = 'http://127.0.0.1:8080';

    export default {
    baseUrl: baseUrl,
    adminClient: {
    baseUrl: baseUrl,
    realmName: 'master',
    username: 'admin',
    password: 'admin',
    grantType: 'password',
    clientId: 'admin-cli'
    }
    };
    然后编写create-realm.js:
    1
    2
    3
    4
    5
    6
    import { readFileSync } from 'node:fs';
    import adminClient from './keycloak-admin-client.js';

    await adminClient.realms.create(
    JSON.parse(readFileSync(new URL('../config/realm-import.json', import.meta.url), 'utf8'))
    );
    代码从real-import.json中读入需要创建的数据,使用adminClient.realms.create方法进行创建。
    删除realm的代码如下:
    1
    2
    3
    import adminClient from './keycloak-admin-client.js';

    await adminClient.realms.del({ realm : 'xlf' });

导入数据的json示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{
"realm": "xlf",
"enabled": true,
"clients": [
{
"clientId": "resource-server",
"enabled": true,
"bearerOnly": false
},
{
"clientId": "spa",
"enabled": true,
"publicClient": true,
"directAccessGrantsEnabled": true,
"redirectUris": [ "http://localhost:5173/*" ]
},
{
"clientId": "test-cli",
"enabled": true,
"publicClient": true,
"directAccessGrantsEnabled": true
}
],
"users" : [
{
"username" : "user1",
"enabled": true,
"email" : "sys@test.org",
"firstName": "user",
"lastName": "user",
"credentials" : [
{ "type" : "password",
"value" : "12345" }
],
"realmRoles": [ "user", "offline_access" ],
"clientRoles": {
"account": [ "manage-account" ]
}
}],
"roles" : {
"realm" : [
{
"name": "user",
"description": "User privileges"
},
{
"name": "admin",
"description": "Administrator privileges"
}
]
}

vue集成

首先需要安装keycloak,可以使用docker安装。然后创建realm和client。

然后创建vue3项目
npm init vue@latest。
在项目中安装keycloak.js:
npm install keycloak-js

然后,在main.js中声明keycloak:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

import Keycloak from "keycloak-js";

const keycloak = new Keycloak({
url: "http://localhost:8080",
realm: "quickstart",
clientId: "spa",
});
window['keycloak'] = keycloak;
await keycloak.init({ onLoad: "login-required" });

const app = createApp(App)

app.use(router)

app.mount('#app')

注意,使用window保存keycloak全局变量,这样在其它页面可以通过这个变量访问keycloak。

比如,访问用户的accesstoken:
keycloak.token
如果解析token:
keycloak.tokenParsed
还可以访问idtoken:
keycloak.idTokenParsed

使用accesstoken可以访问资源服务器。首先安装axios,然后通过axios访问资源:

1
2
3
4
5
6
7
8
9
10
11
12
created: async function () {
var keycloak = window['keycloak']

this.token = keycloak.tokenParsed

const res = await axios({
url: "http://localhost:3000/secured",
method: 'get',
headers: {
Authorization: " Bearer " + keycloak.token
}
})

接下来可以创建资源服务器。

资源服务器

可以使用keycloak创建资源服务器。首先创建node.js express项目,安装如下依赖:

  • keycloak-connect
  • cors

app.js的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import express from 'express';
import Keycloak from 'keycloak-connect';
import cors from 'cors'

const app = express();
const port = 3000;

// Middleware configuration loaded from keycloak.json file.
const keycloak = new Keycloak({});

app.use(keycloak.middleware());
app.use(cors());

app.get('/public', (req, res) => {
res.json({message: 'public'});
});

app.get('/secured', keycloak.protect('realm:user'), (req, res) => {
const username = req.kauth.grant.access_token.content.preferred_username;
res.send(`Hello, ${username}!`);
//res.json({message: 'secured'});
});

app.get('/admin', keycloak.protect('realm:admin'), (req, res) => {
res.json({message: 'admin'});
});

app.use('*', (req, res) => {
res.send('Not found!');
});

app.listen(port, () => {
console.log(`Listening on port ${port}.`);
});

keycloak的配置信息从keycloak.json文件中读入:

1
2
3
4
5
6
7
{
"realm": "quickstart",
"bearer-only": true,
"auth-server-url": "http://localhost:8080",
"ssl-required": "none",
"resource": "spa"
}

注意,auth-server-url需要与访问客户端配置的认证服务一致。