У меня есть решение, но это похоже на ужасный взлом. Тем не менее, это работает, и мне нужно получить это через черту. Если кто-нибудь может предложить улучшение или альтернативный подход, я был бы признателен.
Мы начнем с базового c Express сервера (размещенного на 4005), который может проверять пользователя через Passport-SAML SSO :
const express = require('express');
const jwt = require('jsonwebtoken')
const passport = require('passport');
const Strategy = require('passport-saml').Strategy;
require('dotenv').config()
const signature = process.env.SIGNATURE
const expiresIn = process.env.EXPIRESIN
// Simplification: actually there's a db look-up here
// based on req.user in order to get just the id
// but you get the idea
const createToken = user =>
jwt.sign({ user.email }, signature, { expiresIn: expiresIn })
passport.use('saml2', new Strategy({
path: 'http://localhost:4005/assert',
entryPoint: 'https://sso.connect.pingidentity.com/sso/idp/SSO.saml2?idpid=XXXX_YOURVALUEHERE_XXXX',
issuer: 'XXXX_YOURIDHERE_XXXX',
audience: 'XXXX_YOURIDHERE_XXXX',
},
function(profile, cb) {
return cb(null, profile);
}));
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
// Create a new Express application.
var app = express();
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
// Initialize Passport and restore authentication state, if any, from the
// session.
app.use(passport.initialize());
app.get('/login/idp', passport.authenticate('saml2'));
app.post('/assert',
passport.authenticate('saml2',
{ failureRedirect: `http://localhost:3000/?error=unauthenticated` } ),
function(req, res) {
const token = createToken(req.user)
res.redirect(`http://localhost:3000/signinOK?token=${token}`);
});
app.listen(4005);
Затем в папке React src
добавьте требуемый setupProxy. js:
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/login',
createProxyMiddleware({
target: 'http://localhost:4005',
headers: {
"Connection": "keep-alive"
}
})
);
};
Затем в приложении React (размещенном на порте 3000) мы создаем простой компонент кнопки для главной страницы:
import React from 'react'
import { Button } from '@material-ui/core'
function StartBtn() {
return (
<Button type="submit" variant="contained" color="primary" >
<a href="/login/idp">Login</a>
</Button>
)
}
export default StartBtn
На этом этапе мы прикрепляем <StartBtn />
на первой странице и настраиваем маршрут, который реагирует на http://localhost:3000/signinOK?token=...
, захватывая токен, используя что в качестве значения в любой последующей bearer:
аутентификации и перенаправления на основной сайт.
Поток выглядит следующим образом:
- Пользователь загружает первую страницу и нажимает
<StartBtn/>
; - Ссылка перенаправляется благодаря
setupProxy.js
на сервер Express; - Express сервер делает попытку аутентификации
Passport-SAML
; - Результат Процесс аутентификации - это POST-вызов от IdP (сервера аутентификации PingID) к * 1 Сервер 048 *, на маршруте
/assert
. - Результат либо успешен, либо неудачен, но в обоих случаях перенаправляет в приложение React.
- В случае успеха данные пользователя возвращаются как JWT; или
- В случае сбоя возвращается ошибка.
Я вернусь к этому ответу, если смогу найти способы его улучшить, или расширить на этапе JWT .
Я надеюсь, что кто-то либо (а) сочтет это полезным, либо (б) придумает машину времени, вернется и отправит сообщения за эти 3 недели go, чтобы я мог сэкономить больше своих оставшихся волосяные фолликулы. Или (c) говорит мне, как я должен был это сделать.