如何使用 nodejs 和 okta 进行应用注销

How to do an app logout using nodejs and okta

我目前正在使用 Okta 与 OIDC 和 Node Express 来登录我制作的 Web 应用程序。我希望我的用户能够注销我的应用程序而不是 okta 本身,因为 okta 是我公司的,这将使他们从使用公司 okta 的所有其他网站注销。 Okta 建议在他们的网站上执行此操作。

app.get('/local-logout', (req, res) => {
  req.logout();
  res.redirect('/');
});

(https://developer.okta.com/docs/guides/sign-users-out/nodeexpress/sign-out-of-your-app/)

我试过实现这个但它不起作用。我也尝试过使用 req.session.destroy、res.clearCookie("connect.sid")、req.session = null 以及这些有或没有回调的许多不同组合。每当我重定向时,它都会返回主页并登录同一用户。每当我尝试删除 connect.sid cookie 时,它​​都会删除,然后在用户被重定向时重新初始化。我不太确定该怎么做。下面是我删除了不相关端点的代码。


require('dotenv').config();

import 'zone.js/dist/zone-node';

import { ngExpressEngine } from '@nguniversal/express-engine';
import { join } from 'path';
import * as express from 'express';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync, read } from 'fs';


// 30 minutes
const sessionMaxAge = 1800000;

import * as e from 'cors';
import { resolveForwardRef } from '@angular/core';
import { User } from '@okta/okta-sdk-nodejs';

const session = require('express-session');
const { ExpressOIDC } = require('@okta/oidc-middleware');
const cookieParser = require("cookie-parser");


 /** Creates the OpenID Connect Middleware and configures it to work with Okta */
 const oidc = new ExpressOIDC({
  appBaseUrl: process.env.HOST_URL,
  issuer: `${process.env.OKTA_ORG_URL}/oauth2/default`,
  client_id: process.env.OKTA_CLIENT_ID,
  client_secret: process.env.OKTA_CLIENT_SECRET,
  redirect_uri: process.env.REDIRECT_URL,
  scope: 'openid profile',
  routes: {
    loginCallback: {
      path: '/authorization-code/callback'
    },
  }
});


// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  var root_folder: string = process.env.ROOT_FOLDER || "dist/angular-app/browser"
  const server = express();
  const distFolder = join(process.cwd(), root_folder);
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

  // Our Universal express-engine (found @ https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_angular_universal_tree_master_modules_express-2Dengine&d=DwIGAg&c=-35OiAkTchMrZOngvJPOeA&r=03NdPO1x-l0QAZ_R9TNGwA&m=WF5ia-YADjCituVWMV5vLoZ5wg7d_W1qhCYDTbJNGT0&s=WPOkeRsetPDQ6TrD26RKLo1m9_zxBfQXGhUUSkth0Ew&e= )
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
  }));

  server.set('view engine', 'html');
  server.set('views', distFolder); 

  // Serve static files from /browser
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }));

  // Configure Session Support
  server.use( session({
      secret: process.env.APP_SECRET,
      resave: false,
      saveUninitialized: false,
      cookie: {maxAge: sessionMaxAge}
    })
  );
  
  server.use(cookieParser());
  server.use(oidc.router);

   // Log the user out of the local session
   server.get('/local-logout',(req:any, res:any) => {
    req.logout();
    res.redirect('/');
  });

  // All regular routes use the Universal engine
  server.get('*', oidc.ensureAuthenticated({ redirectTo: '/login' }), (req: any, res: any) => {
    if(req.session && req.session.username != null) {
      console.log(process.env);
      res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
    }
    else {
      console.log("getting user info");
      getUserInfo(req)
      .then(userInfo => {
        req.session.username = userInfo.username;
        req.session.group = userInfo.group;
        if (userInfo.group=="unauthorized") {
          res.sendFile('./403.html', {root: "."})
        }
        else{
          console.log(process.env);
          res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
        }
      });
  }
  });

  return server;
}
  function run(): void {
    const port = process.env.PORT || 4000;

    // Start up the Node server
    const server = app();
    server.listen(port, () => {
      console.log(`Node Express server listening on https://urldefense.proofpoint.com/v2/url?u=http-3A__localhost-3A-24-257Bport-257D&d=DwIGAg&c=-35OiAkTchMrZOngvJPOeA&r=03NdPO1x-l0QAZ_R9TNGwA&m=WF5ia-YADjCituVWMV5vLoZ5wg7d_W1qhCYDTbJNGT0&s=PUb7XMS4uP9ICqUY28QgXNRxoWk6sGatPdmZMqmgbJs&e= `);
    });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run();
}

export * from './src/main.server';

经过详尽的搜索,我认为这是不可能的。我最终做了 req.logout(),然后重定向到一个页面,上面写着“您已退出应用程序,但可能仍登录到您的单点登录提供商。”