OpenID 공급자에 리소스 서버 추가
.env
파일을 업데이트하는 것을 잊지 마십시오.구성 업데이트
리소스 서버용으로 별도의 클라이언트를 생성합니다. 이 클라이언트는 리소스에만 액세스할 수 있는 제한된 클라이언트입니다. 이 클라이언트에서는 새 토큰을 발급할 수 없습니다. 또한 이를 제거하여 리소스에 대한 모든 사용자 액세스를 취소할 수 있습니다. 토큰의 유효성을 검사할 수 있는 검사 기능을 활성화했습니다. resourceIndicators는 리소스 서버를 정의한 것입니다.
./oidc/src/configs/configuration.ts
export const configuration: Configuration = {
clients: [
{
client_id: "api",
client_secret: "night-wolf",
redirect_uris: [],
response_types: [],
grant_types: ["client_credentials"],
scope: "openid email profile phone address",
},
],
features: {
introspection: {
enabled: true,
allowedPolicy(ctx, client, token) {
if (
client.introspectionEndpointAuthMethod === "none" &&
token.clientId !== ctx.oidc.client?.clientId
) {
return false;
}
return true;
},
},
resourceIndicators: {
defaultResource(ctx) {
return Array.isArray(ctx.oidc.params?.resource)
? ctx.oidc.params?.resource[0]
: ctx.oidc.params?.resource;
},
getResourceServerInfo(ctx, resourceIndicator, client) {
return {
scope: "api:read offline_access",
};
},
},
},
};
API 서비스 추가
API 서버를 실행하려면 다음 단계를 따르십시오.
./api
디렉토리 아래에 모든 것을 설정합니다.1. 종속성 추가
$ yarn add koa
$ yarn add @types/koa -D
2. 컨트롤러 추가
우리는 모의 서비스를 만들 것입니다. 그것은 PI 번호를 반환하고 우리는 그것을 일급 비밀 정보로 취급합니다!
./api/src/controllers/api.controller.ts
import { Middleware } from "koa";
export default (): { [key: string]: Middleware } => ({
pi: async (ctx) => {
ctx.status = 200;
ctx.message = Math.PI.toString();
},
});
3. 미들웨어 추가
우리는 마법의 부분에 도달했습니다! 여기에서 사용자가 리소스에 액세스할 수 있는지 확인합니다. 그런 다음 세션 정보를 체인의 다음 컨트롤러로 전달합니다.
./api/src/middlewares/auth.middleware.ts
import { Middleware } from "koa";
import fetch from "node-fetch";
export const authenticate: Middleware = async (ctx, next) => {
const body = new URLSearchParams();
if (!ctx.request.headers.authorization) return ctx.throw(401);
body.append(
"token",
ctx.request.headers.authorization.replace(/^Bearer /, "")
);
body.append("client_id", process.env.CLIENT_ID as string);
body.append("client_secret", process.env.CLIENT_SECRET as string);
const url = `${process.env.AUTH_ISSUER}/token/introspection`;
const response = await fetch(url, {
method: "POST",
headers: {
["Content-Type"]: "application/x-www-form-urlencoded",
},
body: body,
});
if (response.status !== 200) ctx.throw(401);
const json = await response.json();
const { active, aud } = json;
// Resource URI and audience (aud) must be equal
if (active && aud.trim() === ctx.request.href.split("?")[0]) {
ctx.state.session = json;
await next();
} else {
ctx.throw(401);
}
};
// Check if scope is valid
export const authorize =
(...scopes: string[]): Middleware =>
async (ctx, next) => {
if (
ctx.state.session &&
scopes.every((scope) => ctx.state.session.scope.includes(scope))
) {
await next();
} else {
ctx.throw(401);
}
};
4. 라우터 추가
여기서 라우터를 컨트롤러에 바인딩합니다. 또한
./pi
컨트롤러에 필요한 범위를 제공합니다../api/src/routes/api.router.ts
import Router from "koa-router";
import apiController from "../controllers/api.controller";
import { authenticate, authorize } from "../middlewares/auth.middleware";
export default () => {
const router = new Router();
const { pi } = apiController();
router.get("/pi", authenticate, authorize("api:read"), pi);
return router;
};
./api/src/routes/index.ts
import Router from "koa-router";
import appRouter from "./api.router";
export default () => {
const router = new Router();
router.use(appRouter().routes());
return router;
};
5. 서버 시작
서버 시작 스크립트
./api/src/index.ts
import cors from "@koa/cors";
import dotenv from "dotenv";
import Koa from "koa";
import path from "path";
import router from "./routes";
dotenv.config({ path: path.resolve("api/.env") });
const app = new Koa();
app.use(cors());
app.use(router().routes());
app.listen(process.env.PORT, () => {
console.log(
`api listening on port ${process.env.PORT}, check http://localhost:${process.env.PORT}`
);
});
앱에 서비스 페이지 추가
마지막으로 PI 리소스에 액세스하기 위해 API 서버에 액세스하는 소비자 앱을
./app
디렉토리 아래에 생성합니다.HTML 파일 추가
./app/src/views/pi.ejs
<!DOCTYPE html>
<html>
<%- include('components/head'); -%>
<body class="app">
<div class="login-card">
<h1><%= title %></h1>
<form autocomplete="off">
<label>Token</label>
<input id="token" required name="token" placeholder="Token" />
<p id="pi" style="margin-top: 0">Value: -</p>
<button type="button" class="login login-submit" onclick="onClick()">
Fetch
</button>
</form>
</div>
</body>
<script>
async function onClick() {
try {
const response = await fetch("<%= apiUrl %>/pi", {
headers: {
["Authorization"]: `Bearer ${
document.getElementById("token").value
}`,
},
});
if (response.status === 401) {
return alert("You are not authorized to access PI.");
} else if (response.status !== 200) {
return alert(" Failed to fetch PI.");
}
const pi = await response.text();
document.getElementById("pi").innerText = `Value: ${pi}`;
} catch (error) {
alert("Error encountered.");
}
}
</script>
</html>
컨트롤러 추가
./app/src/controllers/app.controller.ts
export default (): { [key: string]: Middleware } => ({
pi: async (ctx) => {
return ctx.render("pi", { title: "PI", apiUrl: process.env.API_URL });
},
});
라우터 추가
./app/src/routes/app.router.ts
export default () => {
const router = new Router();
const { pi } = appController();
router.get("/pi", pi);
return router;
};
요약
이 섹션에서는 제한된 리소스로 PI 번호가 있는 리소스 서버를 생성했습니다. 그런 다음 이를 인증 서버와 통합하여 사용자 액세스 권한을 부여했습니다. 결과를 보기 위해 우리는 모든 것을 실제로 볼 수 있는 최소한의 웹 앱을 만들었습니다.
Reference
이 문제에 관하여(OpenID 공급자에 리소스 서버 추가), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ebrahimmfadae/add-a-resource-server-to-an-openid-provider-noo텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)