从SSO重定向到我的本地IP,导致React应用希望通过https

问题描述

我正在通过带有React前端的passport-saml实现saml。当我在本地计算机上的docker容器中运行的saml提供程序(simplesamlPHP)从本地主机运行时,一切工作正常(回调URL为我的应用程序的本地主机:8080)。我在开发网络中运行了另一个saml提供程序(也为simplesamlPHP),该网络将我的静态IP地址回调到该应用程序(仍在localhost:8080上运行)。登录回调工作正常,但是当重定向回到我的快速服务器,并且重定向到我的React应用程序时,所有React资源(.js / .css文件)现在都是https://而不是http:// (通过Chrome开发者工具验证)。这导致没有任何我的反应应用程序资源加载。我想知道这是否可能是Mac通过其网络ip地址寻址时所特有的吗?

快速设置:

const express = require('express');
const http = require('http');
const path = require('path');
const bodyParser = require('body-parser');
const compression = require('compression');
const helmet = require('helmet');
const cors = require('cors');
const passport = require('passport');

require('./passport')(passport);

const app = express();

app.use(cors({
  credentials: true,origin: function(origin,callback){
    return callback(null,true);
  },optionsSuccessstatus: 200,}));
app.use(helmet());
app.use(compression());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.json());
app.use(passport.initialize());
app.use(passport.session());
require('./routes')(app,passport);

if (process.env.NODE_ENV === "production") {
  app.use(express.static(path.join(__dirname,'build')));
  app.get('*',(req,res) => {
    res.sendFile(path.join(__dirname,'build','index.html'));
  });
} else if (process.env.NODE_ENV === "development") {
  app.get('*',res) => {
    res
      .redirect(`http://127.0.0.1:3000`);
  });
}

const httpServer = http.createServer(app);
const port = process.env.PORT || 8080;

httpServer.listen(port,(httpError) => {
  if (httpError) {
    console.error(httpError);
  }
  console.info(`GraphQL Server is Now running on port ${port}`);
  if (typeof process.send === 'function') {
    process.send('ready');
  }
});

const killServer = (signal) => {
  console.info(`Shutting down server: ${signal}`);
  httpServer.close(() => {
    // add additional close processes here
    process.exit(0);
  });
};

process.on('SIGINT',() => {
  killServer('SIGINT');
});

Routes.js:

const SAML = require('passport-saml');
const jwt = require('jsonwebtoken');

module.exports = (app,passport) => {
  app.get('/saml/Metadata',res) => {
    const saml = new SAML({
      issuer: process.env.SAML_ISSUER,callbackUrl: `${process.env.SAML_APP_URL}/login/callback`,logoutCallbackUrl: `${process.env.SAML_APP_URL}/logout/callback`
    });
    const xml = saml.generateServiceProviderMetadata();
    res.set('Content-Type','application/samlMetadata+xml').send(xml);
  });
  
  app.get('/saml/login',passport.authenticate('saml'));
  
  app.post('/login/callback',passport.authenticate('saml',{ failureRedirect: '/error' }),async (req,res) => {
      const {
        error,} = req.user;
      if (error) {
        return res.redirect('/error');
      } else {
        return res.redirect(`/logincb?token=${req.user.token}`);
      }
    });
  
  app.get('/saml/logout',res) => {
    // eslint-disable-next-line no-underscore-dangle
    const samlStrategy = passport._strategy('saml');
    return samlStrategy.logout(req,(err,reqUrl) => {
      if (err) {
        return res.redirect('/error');
      }
      req.logout();
      return res.redirect(reqUrl);
    });
  });
  
  app.all('/logout/callback',res) => {
    req.logout();
    return res.redirect('/');
  });

  app.get('/user',res) => {
    const tokenStr = req.header('Authorization').split(' ');
    const token = tokenStr[1];
    try {
      const decoded = jwt.verify(token,process.env.APP_SECRET);
      return res
        .json({ user: decoded });
    } catch(err) {
      return res
        .status(401)
        .json( {error: 'Invalid JWT' });
    }
  });
}

passport.js:

const https = require('https');
const os = require('os');
const Metadata = require('passport-saml-Metadata');
const { Strategy: SamlStrategy } = require('passport-saml');
const { Strategy: JWTStrategy,ExtractJwt } = require('passport-jwt');
const jwt = require('jsonwebtoken');
const axios = require('axios');
const fileCache = require('file-system-cache').default;

const client = axios;
const clientProxy = axios.create({
  proxy: false,httpsAgent: new https.Agent({
    rejectUnauthorized: false,}),});

const config = {
  issuer: process.env.SAML_ISSUER,path: '/login/callback',logoutCallbackUrl: '/logout/callback',Metadata: {
    client: process.env.SAML_MetaDATA_PROXY && process.env.SAML_MetaDATA_PROXY === "proxy" ? clientProxy : client,url: `${process.env.SAML_MetaDATA}?PartnerSpId=${process.env.SAML_ISSUER}`,timeout: 5000,backupStore: fileCache({
      basePath: os.tmpdir(),ns: process.env.SAML_ISSUER
    })
  }
}

module.exports = (passport) => {
  Metadata.fetch(config.Metadata)
    .then(async (reader) => {
      const strategyConfig = Metadata.toPassportConfig(reader);
      strategyConfig.issuer = config.issuer;
      strategyConfig.callbackUrl = process.env.SAML_APP_URL + config.path;
      strategyConfig.logoutCallbackUrl = process.env.SAML_APP_URL + config.logoutCallbackUrl;
      strategyConfig.protocol = 'saml2';
      strategyConfig.acceptedClockSkewMs = -1;

      const jwtConfig = {
        secretorKey: process.env.APP_SECRET,jwtFromrequest: ExtractJwt.fromAuthHeaderAsBearerToken(),issuer: config.issuer,audience: process.env.SAML_APP_URL,};

      const samlStrategy = new SamlStrategy(
        strategyConfig,async (profile,done) => {
          const { nameID,nameIDFormat } = profile;
          // use nameId to look up user on database
          const user = {
            uid: nameID.toLowerCase(),nameID,nameIDFormat,auth: 'something'
          };
          const token = await jwt.sign(
            user,process.env.APP_SECRET,{
              expiresIn: '12h',issuer: process.env.SAML_ISSUER,}
          );
          user.token = token;
          
          return done(null,user);
        }
      );

      const jwtStrategy = new JWTStrategy(
        jwtConfig,async (jwtPayload,done) => done(null,jwtPayload)
      );

      passport.use('saml',samlStrategy);
      passport.use('jwt',jwtStrategy);

      passport.serializeUser((user,done) => {
        done(null,user);
      });

      passport.deserializeUser(async (user,user);
      });
    })
    .catch((err) => {
      console.error('Error loading SAML Metadata',err);
      process.exit(1);
    });
};

react应用目前是标准的create-react-app,在package.json上设置了以下内容

"homepage": ".","proxy": "http://127.0.0.1:8080"

和1个回调路由:

import React,{ useEffect,useState } from 'react';
import { Redirect,useLocation } from 'react-router-dom';

const LoginCB = () => {
  const location = useLocation();
  const { search } = location;
  const params = new URLSearchParams(search);
  const token = params.get('token');

  const [redirect,setRedirect] = useState(false);

  useEffect(() => {
    fetch('/user',{
      headers: {
        Authorization: `Bearer ${token}`
      }
    })
      .then(res => res.json())
      .then(data => {
        console.log(data);
        setRedirect(true)
      });
  },[token]);

  return (
    <div>
      {redirect ? (
        <Redirect
          to={'/'}
        />
      ) : null}
      <span>something</span>
    </div>
  )
}

export default LoginCB;

screenshot on chrome showing https for resources

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...