Use dynamic redirectUri
This commit is contained in:
@@ -10,7 +10,6 @@ services:
|
|||||||
- OIDC_WELL_KNOWN_URL=
|
- OIDC_WELL_KNOWN_URL=
|
||||||
- CLIENT_ID=
|
- CLIENT_ID=
|
||||||
- CLIENT_SECRET=
|
- CLIENT_SECRET=
|
||||||
- REDIRECT_URI=http://127.0.0.1:3000/callback
|
|
||||||
- COOKIE_SECRET=
|
- COOKIE_SECRET=
|
||||||
network_mode: host
|
network_mode: host
|
||||||
restart: always
|
restart: always
|
||||||
|
|||||||
34
index.js
34
index.js
@@ -8,11 +8,9 @@ require("dotenv").config();
|
|||||||
|
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
const COMPUTER_NAME = process.env.COMPUTER_NAME || "MyComputer";
|
const COMPUTER_NAME = process.env.COMPUTER_NAME || "MyComputer";
|
||||||
const REDIRECT_URI =
|
|
||||||
process.env.REDIRECT_URI || "http://127.0.0.1:3000/callback";
|
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
app.use(express.json());
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
secret: process.env.COOKIE_SECRET,
|
secret: process.env.COOKIE_SECRET,
|
||||||
@@ -32,7 +30,6 @@ let client;
|
|||||||
client = new issuer.Client({
|
client = new issuer.Client({
|
||||||
client_id: process.env.CLIENT_ID,
|
client_id: process.env.CLIENT_ID,
|
||||||
client_secret: process.env.CLIENT_SECRET,
|
client_secret: process.env.CLIENT_SECRET,
|
||||||
redirect_uris: [REDIRECT_URI],
|
|
||||||
response_types: ["code"],
|
response_types: ["code"],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -49,18 +46,39 @@ let client;
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/login", (req, res) => {
|
const stateMap = {};
|
||||||
|
|
||||||
|
app.post("/authorize", (req, res) => {
|
||||||
|
const { redirectUri } = req.body;
|
||||||
|
if (!redirectUri) {
|
||||||
|
return res.send(
|
||||||
|
renderHtml("login-fail.html", {
|
||||||
|
COMPUTER_NAME,
|
||||||
|
ERROR: "redirectUri missing or invalid",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = Math.random().toString(36).substring(2);
|
||||||
|
stateMap[state] = { redirectUri };
|
||||||
|
|
||||||
const url = client.authorizationUrl({
|
const url = client.authorizationUrl({
|
||||||
scope: "openid profile",
|
scope: "openid profile",
|
||||||
redirect_uri: REDIRECT_URI,
|
redirect_uri: redirectUri,
|
||||||
|
state,
|
||||||
});
|
});
|
||||||
res.redirect(url);
|
|
||||||
|
// 回傳 JSON 給前端,讓前端負責導向
|
||||||
|
res.json({ redirect: url });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/callback", async (req, res) => {
|
app.get("/callback", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
const state = req.query.state;
|
||||||
|
const { redirectUri } = stateMap[state];
|
||||||
|
|
||||||
const params = client.callbackParams(req);
|
const params = client.callbackParams(req);
|
||||||
const tokenSet = await client.callback(REDIRECT_URI, params);
|
const tokenSet = await client.callback(redirectUri, params, { state });
|
||||||
const userinfo = await client.userinfo(tokenSet.access_token);
|
const userinfo = await client.userinfo(tokenSet.access_token);
|
||||||
|
|
||||||
req.session.user = userinfo;
|
req.session.user = userinfo;
|
||||||
|
|||||||
@@ -1,20 +1,51 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>登入 | 喚醒 {{COMPUTER_NAME}}</title>
|
<title>登入 | 喚醒 {{COMPUTER_NAME}}</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif; padding: 1.5rem; font-size: 1.2rem;
|
font-family: sans-serif;
|
||||||
|
padding: 1.5rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
}
|
}
|
||||||
a, button {
|
|
||||||
|
a,
|
||||||
|
button {
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h1>喚醒 {{COMPUTER_NAME}}</h1>
|
<h1>喚醒 {{COMPUTER_NAME}}</h1>
|
||||||
<a href="/login">點此登入</a>
|
<button id="loginBtn">登入</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('loginBtn').addEventListener('click', async function () {
|
||||||
|
const redirectUri = window.location.origin + '/callback';
|
||||||
|
try {
|
||||||
|
const res = await fetch('/authorize', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ redirectUri })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
alert('伺服器錯誤');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (data && data.redirect) {
|
||||||
|
window.location.href = data.redirect;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert('請求失敗: ' + err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user