OpenID 공급자에 리소스 서버 추가

URI를 통해 액세스할 수 있는 모든 엔터티 또는 작업을 리소스라고 합니다. 권한 부여 서버는 유효한 범위를 가진 리소스 소유자에게만 액세스 권한을 부여합니다. .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 번호가 있는 리소스 서버를 생성했습니다. 그런 다음 이를 인증 서버와 통합하여 사용자 액세스 권한을 부여했습니다. 결과를 보기 위해 우리는 모든 것을 실제로 볼 수 있는 최소한의 웹 앱을 만들었습니다.

좋은 웹페이지 즐겨찾기