使用 Sa-Token CORS 策略處理跨域問題(三種方式全版)

前言

之前寫了一篇 使用 Sa-Token 的全局過濾器解決跨域問題(三種方式全版)
詳解了如何使用 Sa-Token 的全局過濾器解決各種跨域問題,正好最近 Sa-Token 更新了版本,最新版本簡化了跨域處理方案,
本文章將介紹一下最新版本的寫法,以便給正在使用新版本的同學(xué)做個參考。

注:本文章僅針對新版本(v1.42.0 及以上版本)提供參考,低于 v1.42.0 版本可以移步上述文章進行了解。


在 web 開發(fā)中,跨域絕對是比較折磨新同學(xué)的一個問題,本文將講解三種常見的跨域情形,并講解如何使用 Sa-Token 框架解決跨域問題。

什么情況下會發(fā)生跨域

簡單理解,就是你在 A 域名下的頁面,去調(diào)用 B 域名的接口,瀏覽器感覺你這次調(diào)用可能是不安全的請求行為,于是它需要用 cors 安全策略來確認一下這個請求是由用戶真實的意愿發(fā)出的,而不是被 csrf 偽造請求攻擊偷偷發(fā)送的。(這么說只是為了方便大家理解,不是特別嚴謹,實際上同域名下部分情形也會出現(xiàn)跨域問題)

請仔細理解上面這段話,因為它說明了兩點:

  • 跨域不是后端接口對前端瀏覽器的限制,而是前端瀏覽器對用戶的限制。
  • 跨域不是在保護后端接口免受攻擊,而是瀏覽器在保護用戶,避免用戶發(fā)送自己不想發(fā)送的請求。

請一定要記住上面跨域的本質(zhì),明白了癥狀和原因,我們才能對癥下藥。

一般情況下,我們會碰到三種跨域場景:

  • 1、本地頁面調(diào)用測試服務(wù)器,只在項目開發(fā)階段會有跨域問題。(比較簡單)
  • 2、使用 header 頭提交 token,產(chǎn)生的跨域問題。(比較常見+通用,推薦使用)
  • 3、使用第三方 Cookie 提交 token,產(chǎn)生的跨域問題。(最古老的方案,目前新版瀏覽器對此方案限制越來越嚴格,非必要不選擇此方案,如果對此方案不是很熟悉就貿(mào)然使用也容易出現(xiàn)安全問題)

跨域情形一:只在項目開發(fā)階段會有跨域問題

有些公司項目的開發(fā)方式為:

  • 在項目開發(fā)時:使用本地頁面調(diào)用測試服務(wù)器接口。(域名不同,存在跨域問題)
  • 在項目部署時:將后端接口和前端頁面部署在同一域名下。(域名一致,不存在跨域問題)

這種情況下比較好解決,在代碼層面我們無需任何更改,只在前端客戶端做出一定的更改就行了。比如說:在前端配置一個代理服務(wù)器,或者修改一下 Chrome 客戶端使其去除跨域限制。

具體的方案有很多,大家可參考這篇博客:手把手教你解決web前端跨域問題

上面是說的普通前后端分離開發(fā),而在APP、小程序 開發(fā)中,其天然就是個沒有跨域限制的客戶端,我們什么都不用做就能解決跨域問題。

跨域情形二:使用 header 頭提交 token,產(chǎn)生的跨域問題(比較常見+通用,推薦使用)

當(dāng)你使用 header 頭提交 token 時,會產(chǎn)生跨域問題。此方案比較常見+通用,推薦使用。

jquery 代碼示例:

    $.ajax({
        url: "/user/getInfo",
        type: "post", 
        data: {},
        dataType: 'json',
        headers: {
            "X-Requested-With": "XMLHttpRequest",
            // 重點處:請求的 header 頭里塞入自定義參數(shù)
            "satoken": localStorage.getItem("satoken")
        },
        success: function(res){
            console.log(res);
        },
        error: function(xhr, type, errorThrown){
            return alert("異常:" + JSON.stringify(xhr));
        }
    });

Axios 代碼示例:

    axios({
        url: "/user/getInfo",
        method: 'post',
        data: {},
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
            // 重點處:請求的 header 頭里塞入自定義參數(shù)
            "satoken": localStorage.getItem("satoken")
        }
    }).
    then(function (response) { // 成功時執(zhí)行
        const res = response.data;
        console.log(res);
    }).
    catch(function (error) {
        return alert("異常:" + JSON.stringify(error));
    })

此時在后端,我們應(yīng)該添加以下響應(yīng)頭:

/**
 * [Sa-Token 權(quán)限認證] 配置類 
 *
 * @author click33
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {

    /**
     * CORS 跨域處理策略
     */
    @Bean
    public SaCorsHandleFunction corsHandle() {
        return (req, res, sto) -> {
            res.
                // 允許指定域訪問跨域資源
                setHeader("Access-Control-Allow-Origin", "*")
                // 允許所有請求方式
                .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                // 有效時間
                .setHeader("Access-Control-Max-Age", "3600")
                // 允許的header參數(shù)
                .setHeader("Access-Control-Allow-Headers", "*");

            // 如果是預(yù)檢請求,則立即返回到前端
            SaRouter.match(SaHttpMethod.OPTIONS)
                .free(r -> System.out.println("--------OPTIONS預(yù)檢請求,不做處理"))
                .back();
        };
    }
}

WebFlux 同理,此處理策略全環(huán)境通用。

跨域情形三:使用第三方 Cookie 提交 token,產(chǎn)生的跨域問題。

這是最古老的方案,目前新版瀏覽器對此方案限制越來越嚴格,非必要不選擇此方案,如果對此方案不是很熟悉就貿(mào)然使用也容易出現(xiàn)安全問題。

jquery 代碼示例:

    $.ajax({
        url: "/user/getInfo",
        type: "post", 
        data: {},
        dataType: 'json',
        // 重點處:指定是跨域模式,需要提交第三方 Cookie 
        crossDomain: true,
        xhrFields:{
            withCredentials: true
        },
        headers: {
            "X-Requested-With": "XMLHttpRequest"
        },
        success: function(res){
            console.log(res);
        },
        error: function(xhr, type, errorThrown){
            return alert("異常:" + JSON.stringify(xhr));
        }
    });

Axios 代碼示例:

    axios({
        url: "/user/getInfo",
        method: 'post',
        data: {},
        // 重點處:開啟第三方 Cookie 
        withCredentials: true,
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        }
    }).
    then(function (response) { // 成功時執(zhí)行
        console.log(res);
    }).
    catch(function (error) {
        return alert("異常:" + JSON.stringify(error));
    })

此時在后端,我們應(yīng)該添加以下響應(yīng)頭:

/**
 * [Sa-Token 權(quán)限認證] 配置類 
 *
 * @author click33
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {

    /**
     * CORS 跨域處理策略
     */
    @Bean
    public SaCorsHandleFunction corsHandle() {
        return (req, res, sto) -> {
            // 獲得客戶端domain
            String origin = req.getHeader("Origin");
            if (origin == null) {
                origin = req.getHeader("Referer");
            }

            // ---------- 設(shè)置跨域響應(yīng)頭 ----------
            res
                // 允許第三方 Cookie
                .setHeader("Access-Control-Allow-Credentials", "true")
                // 允許指定域訪問跨域資源
                .setHeader("Access-Control-Allow-Origin", origin)
                // 允許所有請求方式
                .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                // 允許的header參數(shù)
                .setHeader("Access-Control-Allow-Headers", "x-requested-with,satoken")
                // 有效時間
                .setHeader("Access-Control-Max-Age", "3600")
            ;

            // 如果是預(yù)檢請求,則立即返回到前端
            SaRouter.match(SaHttpMethod.OPTIONS)
                .free(r -> System.out.println("--------OPTIONS預(yù)檢請求,不做處理"))
                .back();
        };
    }

}

WebFlux 同理,此處理策略全環(huán)境通用。

注意:根據(jù)瀏覽器最新標(biāo)準,Cookie 模式認證需要做到以下兩點:

1、Cookie 屬性指定 secure=true 以及 sameSite=None

sa-token:
    is-log: true
    cookie:
        # 指明當(dāng)前為 https 安全連接
        secure: true
        # 指明第三方 Cookie 限制級別為:不限制
        sameSite: None

2、后端的服務(wù)必須是 https 形式,前端無要求。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容