์ฐธ๊ณ ์๋ฃ
- ์ฑ : https://www.yes24.com/Product/Goods/122459785
- ํ ์คํธ ์์ค์ฝ๋: https://github.com/PacktPublishing/Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition
ํตํฉ ๋ฐฉ์ ์ค๋ช
Keycloak๊ณผ ์ ํ๋ฆฌ์ผ์ด์
์ ํตํฉํ ๋, Embedded์ Proxied ๋ฐฉ์์ด ์๋ค.
๊ฐ ๋ฐฉ๋ฒ์ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์กฐ์ ๋ณด์ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ ์ ํํ ์ ์๋ค.
๊ตฌ๋ถ | Embedded | Proxied |
์ค๋ช | ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋ ๋ด์์ Keycloak ์ด๋ํฐ๋ฅผ ์ง์ ์ฌ์ฉํ์ฌ ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ๋ฅผ ์ฒ๋ฆฌํ๋ค. | ์ญ๋ฐฉํฅ ํ๋ก์๋ฅผ ์ฌ์ฉํ์ฌ Keycloak๊ณผ์ ํต์ ์ ์ฒ๋ฆฌํ๋ ์ญ๋ฐฉํฅ ํ๋ก์๋ฅผ ์ค์ ํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์๋จ์์ ์ธ์ฆ์ ์ฒ๋ฆฌํ๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ ๋ ๋ฆฝ์ ์ผ๋ก Keycloak๊ณผ์ ํตํฉ์ ๊ด๋ฆฌํ๋ค. |
์ฅ์ | ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋์์ ์ธ์ฆ ํ๋ฆ์ ์ง์ ์ ์ดํ ์ ์๋ค. ๋ค์ํ ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ ์๋๋ฆฌ์ค๋ฅผ ๊ตฌํํ ์ ์๋ค. |
์ ํ๋ฆฌ์ผ์ด์
์ฝ๋์์ ์ธ์ฆ ๋ก์ง์ ์ ๊ฑฐํ์ฌ ์ฝ๋๊ฐ ๋จ์ํด์ง๋ค. ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ ๋ก์ง์ด ํ๋ก์์์ ์ฒ๋ฆฌ๋๋ฏ๋ก ๋ณด์์ด ๊ฐํ๋๋ค. |
๋จ์ | ๋ณต์ก์ฑ ์ฆ๊ฐ: ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋์ ์ธ์ฆ ๋ก์ง์ด ํฌํจ๋์ด ๋ณต์ก์ฑ์ด ์ฆ๊ฐํ ์ ์๋ค. ๋ณด์ ์ํ: ํด๋ผ์ด์ธํธ ์ธก์์ ์ง์ ํ ํฐ์ ๊ด๋ฆฌํ ๊ฒฝ์ฐ ๋ณด์ ์ํ์ด ์ฆ๊ฐํ ์ ์๋ค. |
ํ๋ก์ ์ค์ ์ด ๋ณต์กํ ์ ์์ผ๋ฉฐ, ์ถ๊ฐ์ ์ธ ์ธํ๋ผ๊ฐ ํ์ํ ์ ์๋ค. ํ๋ก์์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ์์กดํ๊ฒ ๋์ด, ํน์ ์ธ์ฆ ์๋๋ฆฌ์ค๋ฅผ ๊ตฌํํ๋ ๋ฐ ์ ํ์ด ์์ ์ ์๋ค. |
๋ ๋ฐฉ์ ๋ชจ๋ ์ํฉ์ ๋ฐ๋ผ ์ ํํ ์ ์๊ณ , ๋๋ก๋ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค.
Certified OpenID Connect Implementations ์์ ์ธ์ฆ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋๊ฒ์ด ์ข๋ค.
Javascript ์ ํ๋ฆฌ์ผ์ด์ ํตํฉ
์ค์ต ์งํ
์ค์ต์ ์ํด Keycloak์ ์ค๋นํ๋ค.
docker run -p 8080:8080 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak \
start-dev
http://localhost:8080/์ผ๋ก ์ ์ํ์ฌ ์๋ก์ด realm์ ์์ฑํ๋ค. (์ต์ /์๋ต๊ฐ๋ฅ)
์๋ก์ด client๋ฅผ ์์ฑํ๋ค.
- client id: javascript
- root URL: http://localhost:8000
- valid redirect URIs: http://localhost:8000/*
์๋ก์ด ์ฌ์ฉ์๋ ์์ฑํ๋ค.
์ด์ ํ ์คํธ ์ฝ๋๋ฅผ ์ค๋นํ๋ค.
# ํ
์คํธ ์ฝ๋ ๋ค์ด๋ก๋
git clone https://github.com/PacktPublishing/Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition.git
cd ch7/keycloak-js-adapter
realm๊ณผ client๋ฅผ ์์ฑํ์ผ๋, ์ฝ๋๋ ์์ ํด์ฃผ์.
# ch7/keycloak-js-adapter/public/keycloak.json
{
"realm": "myservice",
"auth-server-url": "http://localhost:8080",
"ssl-required": "external",
"resource": "javascript",
"public-client": true
}
# ch7/keycloak-js-adapter/app.js
import express from 'express';
import stringReplace from 'string-replace-middleware';
const app = express();
const port = 8000;
app.use(stringReplace({
KC_URL: process.env.KC_URL || "http://localhost:8080"
}));
app.use('/', express.static('public'));
app.listen(port, () => {
console.log(`Listening on port ${port}.`);
});
keycloak์ ๋ก์ปฌ์ 8080ํฌํธ์์ ์ด์๋๋ฉฐ, ์ดํ๋ฆฌ์ผ์ด์
์ 8000ํฌํธ๋ก ์ฌ๋ผ์ค๊ฒ ๋๋ค.
์ด์ ์คํํด๋ณด์.
# ๊ฒฝ๋ก ์ ๋ค์ด์์๋์ง ํ๋ฒ ๋ ํ์ธ
cd Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition/ch7/keycloak-js-adapter
# ์์
npm install
npm start
๋ธ๋ผ์ฐ์ ์์ http://localhost:8000 ์ ์ํด๋ณด์.
์ ์ํ๋ฉด ๋ฐ๋ก keycloak์ผ๋ก ์ฐ๊ฒฐ๋๋ฉฐ, ๋ก๊ทธ์ธ ํ๋ฉด ํ์ด์ง์ ์ ๊ทผํ ์ ์๊ฒ ๋๋ค.
์ค๋ช
์ฝ๋๋ฅผ ํ์ธํด๋ณด์.
javascript๋ฅผ 8000๋ฒ ํฌํธ๋ก ๋์ฐ๊ธฐ ์ํด ์คํํ๋ ์ด app.js์ฝ๋์์๋
string-replace-middleware๋ฅผ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ ํ์ผ์ ์ ๊ณตํ ๋, ํ์ผ ๋ด์ KC_URL ๋ณ์์ Keycloak ์ฃผ์๋ฅผ ๋ด๋๋ค.
// ch7/keycloak-js-adapter/app.js
import express from 'express';
import stringReplace from 'string-replace-middleware';
const app = express();
const port = 8000;
// ํ๊ฒฝ ๋ณ์ KC_URL์ ์ฌ์ฉํ์ฌ Keycloak ์๋ฒ์ URL์ ์ค์ ํ๋ค.
app.use(stringReplace({
KC_URL: process.env.KC_URL || "http://localhost:8080"
}));
app.use('/', express.static('public'));
app.listen(port, () => {
console.log(`Listening on port ${port}.`);
});
keycloak.json Keycloak ํด๋ผ์ด์ธํธ ์ค์ ์ ํฌํจํ๊ณ ์์ผ๋ฉฐ, Keycloak ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ด๊ธฐํ๋ ๋ ํด๋น ์ค์ ์ ์ฌ์ฉํ๋ค.
(Keycloak JavaScript ์ด๋ํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋์ผ๋ก ๋ก๋ํจ)
์๋ ๋ฐฉ์์ ์๋์ ๊ฐ๋ค.
- Keycloak ์ด๊ธฐํ: index.html์์ Keycloak() ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ init ๋ฉ์๋๋ฅผ ํธ์ถํ ๋, ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก keycloak.json ํ์ผ์ ์ฐพ๋๋ค.
- ์ค์ ๋ก๋: keycloak.json ํ์ผ์ด public ๋๋ ํ ๋ฆฌ์ ์์นํด ์์ผ๋ฉด, Keycloak ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ด ํ์ผ์ ์๋์ผ๋ก ๋ก๋ํ์ฌ ํ์ํ ์ค์ ์ ์ ์ฉํ๋ค.
# ch7/keycloak-js-adapter/public/keycloak.json
{
"realm": "myservice",
"auth-server-url": "http://localhost:8080",
"ssl-required": "external",
"resource": "javascript",
"public-client": true
}
index.html์ Keycloak์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ธ์ฆ์ ์ฒ๋ฆฌํ๋ ์น ํ์ด์ง๋ค. ์ฝ๋๋ ๊ธธ์ด์ ์ค๋ช ๋ง ์ถ๊ฐํ๋ค.
<script src="KC_URL/js/keycloak.js"></script>
์ด ๋ถ๋ถ์์ KC_URL์ app.js์์ ์ค์ ๋ Keycloak ์๋ฒ์ URL๋ก ๋์ฒด๋๋ค.
์ด ๊ณผ์ ์ Keycloak ์ด๊ธฐํ์ ์ผ๋ถ๋ก, Keycloak() ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ init ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ Keycloak์ ์ด๊ธฐํํ๋ค.
์ด๋ keycloak.json ํ์ผ์ด ์๋์ผ๋ก ๋ก๋๋๋ฉฐ, Keycloak JavaScript ์ด๋ํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ก๋๋์ด ํด๋ผ์ด์ธํธ ์ธก์์ Keycloak๊ณผ์ ํต์ ์ ์ฒ๋ฆฌํ ์ ์๊ฒ ๋๋ค.
<!-- ์๋ต -->
document.getElementById("logout").addEventListener("click", () => {
keycloak.logout();
});
document.getElementById("showIdToken").addEventListener("click", () => {
output(keycloak.idTokenParsed);
});
document
.getElementById("showAccessToken")
.addEventListener("click", () => {
output(keycloak.tokenParsed);
});
document
.getElementById("refreshToken")
.addEventListener("click", async () => {
await keycloak.updateToken(-1);
output(keycloak.idTokenParsed);
showProfile();
});
document
.getElementById("showMyAccount")
.addEventListener("click", async () => {
await keycloak.accountManagement()
});
<!-- ์๋ต -->
๋ํ ์ฝ๋๋ด ๋ฒํผ์ ํตํด ํด๋ฆญ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ถ๊ฐํ์ฌ Keycloak์ ๊ธฐ๋ฅ์ ์ํํ ์ ์๋๋ก ํ๋ค.
- ๋ก๊ทธ์์: keycloak.logout()์ ํธ์ถํ์ฌ ์ฌ์ฉ์๋ฅผ ๋ก๊ทธ์์ํ๋ค.
- ํ ํฐ ํ์: keycloak.idTokenParsed)์ ํตํด ํ ํฐ๊ณผ ์ก์ธ์ค ํ ํฐ์ JSON ํ์์ผ๋ก ์ถ๋ ฅํ๋ค.
- ํ ํฐ ๊ฐฑ์ : keycloak.updateToken()์ ํธ์ถํ์ฌ ํ ํฐ์ ๊ฐฑ์ ํ๋ค.
- ๊ณ์ ๊ด๋ฆฌ: keycloak.accountManagement()๋ฅผ ํธ์ถํ์ฌ ์ฌ์ฉ์์ ๊ณ์ ๊ด๋ฆฌ ํ์ด์ง๋ก ์ด๋ํ๋ค.
Nodejs ์ ํ๋ฆฌ์ผ์ด์ ํตํฉ (frontend)
์ค์ต ์งํ
์ค์ต์ ์งํํด๋ณด์.
์ ๋จ๊ณ์์ keycloak์ ๋์ปค๋ก ๋์ฐ๊ณ realm์ ์์ฑํ์ผ๋ ํด๋น ๋จ๊ณ๋ ๊ฑด๋๋ฐ๊ณ ๋ฐ๋ก client๋ถํฐ ์์ฑํ๋ค.
- client id: nodejs
- root URL: http://localhost:8000
- client authentication: on
๋ณด์ client์ด๋ฏ๋ก, Credentials ํญ์์ Secret์ ๋ณต์ฌํด๋๋ค.
์ด์ ์ฝ๋๋ฅผ ์ค๋นํ๋ค.
# ํ
์คํธ ์ฝ๋ ๋ค์ด๋ก๋
git clone https://github.com/PacktPublishing/Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition.git
cd ch7/nodejs/frontend
keycloak ์ค์ ์ ๋ง๊ฒ ์ฝ๋๋ฅผ ์์ ํ๋ค.
์์์ ๋ณต์ ํ client secret์ผ๋ก ๊ฐ์ ๋ณ๊ฒฝํ๊ณ , 8000ํฌํธ์์ ์ ํ๋ฆฌ์ผ์ด์
์ด ์์๋ ์ ์๋๋ก ์ฝ๋๋ฅผ ์์ ํ๋ค.
// ch7/nodejs/frontend/app.js
var express = require('express');
var session = require('express-session');
var Keycloak = require('keycloak-connect');
var cors = require('cors');
var app = express();
app.use(cors());
var memoryStore = new session.MemoryStore();
app.use(session({
secret: 'io9bBSukiwEyUekE62g88aeI4CKYUBTi', // ์์์ ๋ณต์ฌํ client secret ์
๋ ฅ
resave: false,
saveUninitialized: true,
store: memoryStore
}));
var keycloak = new Keycloak({ store: memoryStore });
app.use(keycloak.middleware());
app.get('/', keycloak.protect(), function (req, res) {
res.setHeader('content-type', 'text/plain');
res.send('Welcome!');
});
app.listen(8000, function () { // ์ ํ๋ฆฌ์ผ์ด์
ํฌํธ 8000์ผ๋ก ์์
console.log('Started at port 8000');
});
# ch7/nodejs/frontend/keycloak.json
{
"realm": "myservice",
"auth-server-url": "${env.KC_URL:http://localhost:8080}",
"resource": "nodejs",
"credentials" : {
"secret" : "io9bBSukiwEyUekE62g88aeI4CKYUBTi"
}
}
์ด์ ์คํํด๋ณด์
# ๊ฒฝ๋ก ์ ๋ค์ด์์๋์ง ํ๋ฒ ๋ ํ์ธ
cd Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition/ch7/nodejs/frontend
# ์์
npm install
npm start
๋ก์ปฌ ๋ธ๋ผ์ฐ์ ์์ http://localhost:8000์ ์ ์ํ๋ฉด ์๋์ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
์ค๋ช
๋จผ์ keycloak.json ์ Keycloak ํด๋ผ์ด์ธํธ ์ค์ ์ ํฌํจํ๋ค.
์ javascript ์ค์ต์์๋ keycloak.jsonํ์ผ์ด ์ฌ์ฉ๋์๋๋ฐ ์ด๋ javascriptํ๊ฒฝ์์ ์ฃผ๋ก ์ฌ์ฉ๋๋ ํ์ค์ผ๋ก,
๋ค๋ฅธ ์ธ์ด์์๋ XML๋ฑ์ ํ์์ผ๋ก ์ฌ์ฉํ ์ ๋์๋ค. (์ด๋ํฐ์ ๋ฐ๋ผ ๋ค๋ฆ)
app.js ํ์ผ ๋ด ๋ชจ๋์ด ์ด๊ธฐํ๋ ๋(var keycloak = new Keycloak({ store: memoryStore });)
ํด๋น ์ค์ ์ ์ฌ์ฉํ์ฌ Keycloak ์๋ฒ์์ ํต์ ์ ์ค์ ํ๋ค.
# ch7/nodejs/frontend/keycloak.json
{
"realm": "myservice",
"auth-server-url": "${env.KC_URL:http://localhost:8080}",
"resource": "nodejs",
"credentials" : {
"secret" : "io9bBSukiwEyUekE62g88aeI4CKYUBTi"
}
}
app.js์์๋ keycloak๋ชจ๋์ ๋ถ๋ฌ์ค๊ณ ์ด๊ธฐํ ํ๋ค.
keycloak.json ๊ทธ๋ฆฌ๊ณ app.js ๋ ๊ณณ์์ client secret์ด ๋ชจ๋ ์ฌ์ฉ๋์๋๋ฐ, ๋ชฉ์ ์ด ๋ค๋ฅด๋ค.
- [app.js] Express ์ธ์
์ secret:
- Express์ ์ธ์ ๋ฏธ๋ค์จ์ด๋ ์ฌ์ฉ์ ์ธ์ ์ ๊ด๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
- app.js์ ์ฌ์ฉ๋ secret์ ์ธ์ ID ์ฟ ํค๋ฅผ ์๋ช ํ๋ ๋ฐ ์ฌ์ฉ๋์ด, ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ์ธ์ ๋ฐ์ดํฐ๊ฐ ๋ณ์กฐ๋์ง ์๋๋ก ๋ณดํธํ๋ค.
- [keycloak.json] Keycloak์ secret:
- Keycloak์ secret์ ํด๋ผ์ด์ธํธ ์ธ์ฆ์ ์ํด ์ฌ์ฉ๋๋ค.
- Keycloak ์๋ฒ์ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ์ ์์ ํ ํต์ ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ฉฐ, keycloak.json ํ์ผ์ ์ ์ฅ๋๋ค.
- Keycloak์ด ํด๋ผ์ด์ธํธ๋ฅผ ์๋ณํ๊ณ ์ธ์ฆํ๋ ๋ฐ ํ์ํ๋ค.
var memoryStore = new session.MemoryStore(); ๋ถ๋ถ์ ์ธ์
๋ฐ์ดํฐ๋ฅผ ๋ก์ปฌ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๊ฒ ๋ค๋ ์ค์ ์ด๋ฉฐ,
๋ฉ๋ชจ๋ฆฌ ์คํ ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ๊ฐ๋ฐํ๊ฒฝ์์๋ง ์ฌ์ฉ๋๋ค. (์๋ฒ๊ฐ ์ฌ์์๋๋ฉด ์ธ์
๋ฐ์ดํฐ ๋ชจ๋ ์ง์์ง)
๋ฐ๋ผ์ ๋ณดํต์ ๋ณ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค(Mongodb, rdb, redis) ๋ฑ์ ํ์ฉํ์ฌ ์ธ์
์ ๊ด๋ฆฌํ๋ค.
var express = require('express');
var session = require('express-session');
// Keycloak ๋ชจ๋ ๋ถ๋ฌ์ค๊ธฐ
// ์ด ๋ชจ๋์ Node.js ์ ํ๋ฆฌ์ผ์ด์
์์ Keycloak๊ณผ์ ํตํฉ์ ์ง์ํจ
var Keycloak = require('keycloak-connect');
var cors = require('cors');
var app = express();
app.use(cors());
// ๋ฉ๋ชจ๋ฆฌ์คํ ์ด ์ค์
// ์ธ์
๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ๋ฉ๋ชจ๋ฆฌ ์คํ ์ด๋ฅผ ์์ฑ
var memoryStore = new session.MemoryStore();
app.use(session({
secret: 'io9bBSukiwEyUekE62g88aeI4CKYUBTi',
resave: false,
saveUninitialized: true,
store: memoryStore
}));
// Keycloak ์ธ์คํด์ค ์์ฑ
// Keycloak ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ , ์ธ์
์คํ ์ด๋ฅผ ์ ๋ฌํ๋ค.
// ์ด ์ธ์คํด์ค๋ Keycloak๊ณผ์ ์ํธ์์ฉ์ ๊ด๋ฆฌํ๋ค.
var keycloak = new Keycloak({ store: memoryStore });
// Keycloak ๋ฏธ๋ค์จ์ด ์ฌ์ฉ
// Keycloak ๋ฏธ๋ค์จ์ด๋ฅผ Express ์ ํ๋ฆฌ์ผ์ด์
์ ์ถ๊ฐํ๋ค.
// ์ด ๋ฏธ๋ค์จ์ด๋ ์์ฒญ์ ๊ฐ๋ก์ฑ๊ณ , ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ๋ฅผ ์ฒ๋ฆฌํ๋ค.
app.use(keycloak.middleware());
// Keycloak์ผ๋ก ๋ณดํธํ ๊ฒฝ๋ก ์ค์
// keycloak.protect()๋ฅผ ์ฌ์ฉํ์ฌ ํน์ ๊ฒฝ๋ก๋ฅผ ๋ณดํธํ๋ค.
// ์ด ๊ฒฝ๋ก์ ์ ๊ทผํ๋ ค๋ฉด ์ฌ์ฉ์๊ฐ ์ธ์ฆ๋์ด์ผ ํฉ๋๋ค.
app.get('/', keycloak.protect(), function (req, res) {
res.setHeader('content-type', 'text/plain');
res.send('Welcome!');
});
app.listen(8000, function () {
console.log('Started at port 8000');
});
Nodejs ์ ํ๋ฆฌ์ผ์ด์ ํตํฉ (backend)
์ค์ต ์งํ
์ค์ต์ ์งํํด๋ณด์. ์์์ ์์ฑํ client๋ฅผ ์ฌํ์ฉํ๋ค.
- client id: nodejs
- root URL: http://localhost:8000
- client authentication: on
์ฝ๋๋ฅผ ์ค๋นํ๋ค.
# ํ
์คํธ ์ฝ๋ ๋ค์ด๋ก๋
git clone https://github.com/PacktPublishing/Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition.git
cd ch7/nodejs/backend
keycloak ์ค์ ์ ๋ง๊ฒ ์ฝ๋๋ฅผ ์์ ํ๋ค.
์์์ ๋ณต์ ํ client secret์ผ๋ก ๊ฐ์ ๋ณ๊ฒฝํ๊ณ , 8001ํฌํธ์์ ์ ํ๋ฆฌ์ผ์ด์
์ด ์์๋ ์ ์๋๋ก ์ฝ๋๋ฅผ ์์ ํ๋ค.
// ch7/nodejs/backend/app.js
var express = require('express');
var Keycloak = require('keycloak-connect');
var app = express();
var keycloak = new Keycloak({});
app.use(keycloak.middleware());
app.get('/hello', keycloak.protect(), function (req, res) {
res.setHeader('content-type', 'text/plain');
res.send('Access granted to protected resource');
});
app.listen(8001, function () {
console.log('Started at port 8001');
});
# ch7/nodejs/backend/keycloak.json
{
"realm": "myservice",
"bearer-only": true,
"auth-server-url": "${env.KC_URL:http://localhost:8080}",
"resource": "nodejs"
}
์ด์ ์คํํด๋ณด์.
# ๊ฒฝ๋ก ์ ๋ค์ด์์๋์ง ํ๋ฒ ๋ ํ์ธ
cd Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition/ch7/nodejs/backend
# ์์
npm install
npm start
๋ก์ปฌ ๋ธ๋ผ์ฐ์ ์์ http://localhost:8001์ ์ ์ํ๋ฉด ์๋์ฒ๋ผ Cannot GET / ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
๊ทธ ์ด์ ๋ AccessToken์ด ์๊ธฐ๋๋ฌธ์ด๋ค.
CLI๋ก AccessToken์ ๊ฐ์ ธ์๋ณด์.
# curl -X POST http://localhost:8080/realms/myservice/protocol/openid-connect/token \
# -u "nodejs:io9bBSukiwEyUekE62g88aeI4CKYUBTi" \
# -H "Content-Type: application/x-www-form-urlencoded" \
# -d "username=test01" -d "password=1234" \
# -d "grant_type=password" | jq -r '.access_token'
curl -X POST http://localhost:8080/realms/${realm}/protocol/openid-connect/token \
-u "${client_id}:${client_secret}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=${user_name}" -d "password=${user_password}" \
-d "grant_type=password" | jq -r '.access_token'
๊ฒฐ๊ณผ๋ก Access Token์ ์ป์๋ค. (์ฐธ๊ณ : ๋ธ๋ผ์ฐ์ ๋ฅผ ํตํ์ง ์๊ณ ์ฌ์ฉ์ID/PW๋ฅผ ์ด์ฉํ์ฌ ์ ๊ทผํ ํฐ์ ๋ฐ์ผ๋ ค๋ฉด Direct access grants์ด ํ์ฉ๋์ด์์ด์ผ ํ๋ฉฐ, keycloak์ ๊ธฐ๋ณธ๊ฐ์ด ํ์ฉ์ด๋ค.)
์ด์ ์ด Access Token์ ๊ฐ์ง๊ณ Backend ์๋ฒ์ ์ ๊ทผํด๋ณด์.
# ์์, ๊ฐ ๋ณ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ํ์
# export access_token=$(curl -X POST http://localhost:8080/realms/myservice/protocol/openid-connect/token \
# -u "nodejs:io9bBSukiwEyUekE62g88aeI4CKYUBTi" \
# -H "Content-Type: application/x-www-form-urlencoded" \
# -d "username=test01" -d "password=1234" \
# -d "grant_type=password" | jq -r '.access_token')
export access_token=$(curl -X POST http://localhost:8080/realms/${realm}/protocol/openid-connect/token \
-u "${client_id}:${client_secret}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=${user_name}" -d "password=${user_password}" \
-d "grant_type=password" | jq -r '.access_token')
echo $access_token
curl -v GET http://localhost:8001/hello \
-H "Authorization: Bearer "$access_token
๊ทธ๋ผ ์๋์ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
๋ง์ฝ AccessToken ์์ด ์์ฒญํ๋ค๋ฉด ์คํจํ๊ฒ ๋๋ค.
์ค๋ช
์ฌ๊ธฐ์์ ์ค์ตํ nodejs/backend ๋ Keycloak์ ์ฌ์ฉํด์ ์ฌ์ฉ์๋ฅผ ์ธ์ฆํ๋๊ฒ์ด ์๋,
AccessToken์ ํ์ฉํ์ฌ ์ธ์ฆ๋ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋ฆฌ์์ค ์๋ฒ๋ก์์ ์ญํ ์ ํ๋ค.
// ch7/nodejs/backend/app.js
var express = require('express');
var Keycloak = require('keycloak-connect');
var app = express();
var keycloak = new Keycloak({});
// keycloak ๋ฏธ๋ค์จ์ด ์ฌ์ฉ
app.use(keycloak.middleware());
// ๋ณดํธ๋ ๋ฆฌ์์ค์ ์์ฒญ์ด์ค๋ฉด Keycloak ์๋ฒ์ ํด๋น ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆ
app.get('/hello', keycloak.protect(), function (req, res) {
res.setHeader('content-type', 'text/plain');
res.send('Access granted to protected resource');
});
app.listen(8001, function () {
console.log('Started at port 8001');
});
keycloak.protect()๋ฅผ ์ฌ์ฉํ์ฌ ํน์ ๊ฒฝ๋ก์ ๋ํ ์ ๊ทผ์ ๋ณดํธํ๋ฉฐ, ์๋๋ฐฉ์์ ์๋์ ๊ฐ๋ค.
- AccessToken ์์ : ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ผ ๋, Authorization ํค๋์ AccessToken์ ํฌํจํ๋ค.
- ํ ํฐ ๊ฒ์ฆ: keycloak.protect() ๋ฏธ๋ค์จ์ด๊ฐ ์์ฒญ์ ๊ฐ๋ก์ฑ๊ณ , Keycloak ์๋ฒ์ ํด๋น ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๋ค.
- ์ธ์ฆ ์ฒ๋ฆฌ: ํ ํฐ์ด ์ ํจํ๋ฉด ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ์ ๊ทผ์ด ๊ฑฐ๋ถ๋๋ค.