簡體   English   中英

如何在跨源 SSO 請求中包含身份提供商的 session cookie?

[英]How to include identify provider's session cookie in cross origin SSO request?

我有一個由 Wix 托管的網站,然后是一個 web 應用程序(基於 sveltekit)托管在 Vercel 上。 我喜歡讓 Wix 處理會員資格和付款等事情的簡單性,但我的 webapp 太復雜了,無法在 Wix 上運行。

我想利用 Wix 上的會員登錄工具來允許訪問我的 web 應用程序。 我在 Wix 上創建了一個端點,它檢索登錄用戶的用戶 ID(如果有的話),然后返回帶有用戶 ID 的簽名 JWT。 如果我通過在地址欄中輸入 url(類似於https://www.MyAmazingWebsite.com/_functions/SSO )直接通過我的瀏覽器向該端點發出請求,我將按預期獲得令牌。

但是在我的 web 應用程序中(比方說,托管在https://MyAmazingWebApp.vercel.app ),如果我執行對該端點的fetch ,我會得到一個null令牌,這是沒有用戶登錄時的預期行為。我假設這是因為 MyAmazingWebsite 的 session cookie 沒有與我的跨源fetch一起發送。 在查看了這個SO 問題后,我嘗試按如下方式設置客戶端選項:

  const response = await fetch(url, {
    method: 'GET',
    credentials: 'include'
  })

服務器標頭如下:

  let response = {
      "headers": {
        "Access-Control-Allow-Origin": "https://MyAmazingWebApp.vercel.app",
        "Access-Control-Allow-Credentials": true,
        // also tried "Access-Control-Allow-Credentials": "true",
        "Access-Control-Allow-Headers": "Content-Type, *",
        "Content-Type": "application/json"
      }
  };

但仍然沒有運氣。

是否有可能做到這一點? (“此”使用 session cookie 以跨源方式執行 SSO)。 我曾假設這就是 SSO 的工作方式,至少在某些情況下是這樣。 (例如,如果我已經通過 Google 的身份驗證,使用 Google 進行 SSO 的網站不會要求我再次登錄 Google。但是如果我的瀏覽器沒有發送 session cookie,Google 怎么知道我們在談論誰?我不再填寫登錄表單了嗎?)

編輯:當我考慮更多時,似乎答案可能是“這是不可能的”,並且重定向——不僅僅是 ajax 請求——對於建立我的身份是必要的——通過 session cookie 在同一個origin fashion——並驗證我想授權我的應用程序使用我的 Wix 站點進行 SSO,然后為 web 應用程序生成 session 令牌。這將需要用戶單擊,但不需要重新輸入憑據。值得注意的是,我看到如果我重定向到 SSO 端點而不是fetch它,我會根據需要為登錄用戶獲得一個 JWT 令牌。)

不管一個 CAN 是否共享 cookies 跨源(IIUC 實際上是可能的),這都不是解決此問題的通常(或可能是好的)方法。

以下是我最終如何使用我的 Wix 托管站點作為身份提供者以對最終用戶完全透明且無需接觸的方式為我的 svelte-kit 應用程序實現 SSO 的基礎知識。

注意:我在這上面花費的時間比使用像auth0這樣的供應商來連接具有工業強度的 SSO 花費的時間要多得多。但是,這是有教育意義的,我希望這些努力能夠為其他感興趣的各方闡明 SSO 機制。不用說,我對這段代碼的功能或安全性不做任何保證。顯然,如果你想保護任何有價值的東西,像 auth0 這樣的東西會更合適。)

總體流程是:

Svelte-kit 應用程序重定向到 Wix 站點,傳遞所需的 session 詳細信息作為查詢詞,然后...

Wix 站點驗證是否有用戶登錄,存儲所需的 session 詳細信息,使用 session 令牌作為查詢詞重定向回 App,然后...

應用 POST 令牌返回以獲取身份詳細信息,然后設置 session cookie,並重定向到最初請求的受保護 URI。

執行

首先,在我的 svelte-kit 應用程序中,如果沒有有效的 session cookie,我們將重定向到受保護路由的身份提供者,通過查詢參數跟蹤請求的 URL 和授權端點。 (請注意,HTTP 響應代碼很重要——如果您使用 301,永久重定向將被許多瀏覽器緩存,然后您將“永遠”無法導航回您的受保護路由。)

host.config.js

const BASEURL = "https://MyAmazingWebApp.com/";

export const handle = async ({ event, resolve }) => {const session = 
  event.cookies.get('session');
  const path = event.url.pathname;

  if (!session) {
    const regex = /^\/public/g;
    const pub = path.match(regex);
    if(!pub) {
      throw redirect(307, process.env.HIGHFLASH_SSO_URI + "?" +
                          "requested_url=" + event.url + 
                          "&auth_url=" + BASEURL + "public/auth/sso");
    } else {
      // public route ... proceed with request
      return await resolve(event)
    }
}

現在,在我的 Wix 托管站點上,我創建了一個GET路由來響應后端腳本中的身份驗證請求。

http-functions.js

// Need this to actually get emails. Seems odd, but...
const collection_opts = {
  "suppressAuth": true // !?
}

export async function get_hfpSSO(request) {
  var type, id, session_id;
  const requested_url = request.query.requested_url; 
  const auth_url = request.query.auth_url; 

  // retrieve id of logged in user, if any
  try {
    type = ident.identificationData.identities[0].person.type;
    id = ident.identificationData.identities[0].person.id;
  } catch(e) {
    type = "VISITOR"
  }

  if(type != "VISITOR") {
    /* 
       store the requested session details and the user's id as a 
       signed JWT in a DB (collection) on wix hosted site. Set 
       'session_id' to UUID of this row in DB so we can retrieve 
       these details after successful handshake
    /*

  } else {
      session_id = "";
  }

  let res_options = {
    status: 307,
    headers: {
      "Location" : auth_url + "?session_token=" + session_id
    } 
  };
  return response(res_options);
}

回到我的 svelte-kit 應用程序,我定義了一個端點來接收身份驗證令牌並通過 POST 完成握手。 (我不知道這最終是否比僅使用查詢術語更安全,而且我還沒有研究 browser.network 流量來驗證)。 注意:握手完成后,我使用 HTML 元刷新標簽到 go 到最初請求的頁面而不是重定向,因為我需要設置一個 cookie。 我無法設置帶有重定向響應的 cookie。

POST 返回的數據包括一個簽名的 JWT,我使用本地存儲的相應公鑰對其進行驗證。

$src/routes/public/sso/+server.js

import jwt from 'jsonwebtoken';
import fs from 'fs';
import { nanoid } from 'nanoid';

const BASEURL = "https://MyAmaxingWebApp.com/";

export async function GET({ request, url }) {
  var session_token, destination;
  const idp_session_token = url.searchParams.get('session_token');

  if(idp_session_token) {
    const response = await fetch("https://www.highflowpeds.com/_functions/hfpSSO", 
      {
         method: 'POST',
         headers: { "Content-Type": "application/json" },
        body: JSON.stringify({"session_token": idp_session_token})
      })
    const body = await response.json();
    const session = {token: body.auth_token, destination: body.destination};
    try {
      // verify JWT signature of session.token, then...
      session_token = nanoid();
      destination = session.destination;
    } catch(err) {
        session_token = "";
        destination = BASEURL + "public/auth/login";
    }
  } else {
    session_token = "";
    destination = BASEURL + "public/auth/login";
  }

  
  let res = new Response("<html><head><meta http-equiv='Refresh' content='0; url=" + destination + "'><head></html>");
  res.headers.append("Content-Type", "text/html; charset=utf-8");
  res.headers.append("Set-Cookie", "session=" + session_token + "; SameSite=Lax; HttpOnly; Path=/; Max-Age=86400");
  return res;
}

在 Wix 站點端,這是一個 POST 端點,它以簽名 JWT 的形式提供身份詳細信息,以響應有效的 session 令牌:


export async function post_hfpSSO(request) {
  let response;
  const d = await request.body.json();
  const session_token = d.session_token;
  if (session_token) {

    // loading up the session details I saved to DB during the initial GET request.
    const session = await wixData.query("SSO_sessions")  
                    .eq("session_id", session_token)
                    .find(collection_opts);
    response = {
      body: {auth_token: session.items[0].auth_token, destination: session.items[0].destination},
      headers: {
        "Content-Type": "application/json"
      }
    };
  } else {
    response = {
      body: {auth_token: "", destination: ""},
      headers: {
        "Content-Type": "application/json"
      }
    }
  };
  return ok(response);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM