国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
前后端分離 | 關(guān)于登錄狀態(tài)那些事

前后端分離 | 關(guān)于登錄狀態(tài)那些事

一、背景

登錄是一個(gè)網(wǎng)站最基礎(chǔ)的功能。有人說它很簡單,其實(shí)不然,登錄邏輯很簡單,但涉及知識(shí)點(diǎn)比較多,如: 密碼加密、cookie、session、token、JWT等。

我們看一下傳統(tǒng)的做法,前后端統(tǒng)一在一個(gè)服務(wù)中:

如圖所示,邏輯處理和頁面放在一個(gè)服務(wù)中,用戶輸入用戶名、密碼后,后臺(tái)服務(wù)在session中設(shè)置登錄狀態(tài),和用戶的一些基本信息, 然后將響應(yīng)(Response)返回到瀏覽器(Browser),并設(shè)置Cookie。下次用戶在這個(gè)瀏覽器(Browser)中,再次 訪問服務(wù)時(shí),請(qǐng)求中會(huì)帶上這個(gè)Cookie,服務(wù)端根據(jù)這個(gè)Cookie就能找到對(duì)應(yīng)的session,從session中取得用戶的信息,從而 維持了用戶的登錄狀態(tài)。這種機(jī)制被稱作Cookie-Session機(jī)制。

近幾年,隨著前后端分離的流行,我們的項(xiàng)目結(jié)構(gòu)也發(fā)生了變化,如下圖:

我們?cè)L問一個(gè)網(wǎng)站時(shí),先去請(qǐng)求靜態(tài)服務(wù),拿到頁面后,再異步去后臺(tái)請(qǐng)求數(shù)據(jù),最后渲染成我們看到的帶有數(shù)據(jù)的網(wǎng)站。在這種結(jié)構(gòu)下, 我們的登錄狀態(tài)怎么維持呢?上面的Cookie-Session機(jī)制還適不適用?

這里又分兩種情況,服務(wù)A和服務(wù)B在同一域下,服務(wù)A和服務(wù)B在不同域下。在詳細(xì)介紹之前,我們先普及一下瀏覽器的同源策略。

二、同源策略

同源策略是瀏覽器保證安全的基礎(chǔ),它的含義是指,A網(wǎng)頁設(shè)置的 Cookie,B網(wǎng)頁不能打開,除非這兩個(gè)網(wǎng)頁同源。 所謂同源是指:

  • 協(xié)議相同
  • 域名相同
  • 端口相同

例如:http://www.a.com/login,協(xié)議是http,域名是www.a.com,端口是80。只要這3個(gè)相同,我們就可以在請(qǐng)求(Request)時(shí)帶上Cookie, 在響應(yīng)(Response)時(shí)設(shè)置Cookie。

三、同域下的前后端分離

我們了解了瀏覽器的同源策略,接下來就看一看同域下的前后端分離,首先看服務(wù)端能不能設(shè)置Cookie,具體代碼如下:

后端代碼:

1
2
3
4
5
6
7
@RequestMapping('setCookie')
public String setCookie(HttpServletResponse response){
    Cookie cookie = new Cookie('test','same');
    cookie.setPath('/');
    response.addCookie(cookie);
    return 'success';
}

我們?cè)O(shè)置Cookie的path為根目錄”/”,以便在該域的所有路徑下都能看到這個(gè)Cookie。

前端代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <title>test</title>
    <script src='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js'></script>
    <script>
        $(function () {
            $.ajax({
                url : '/test/setCookie',
                method: 'get',
                success : function (json) {
                    console.log(json);
                }
            });
        })
    </script>
</head>
<body>
    aaa
</body>
</html>

我們?cè)跒g覽器訪問http://www.a.com:8888/index.html,訪問前先設(shè)置hosts,將www.a.com指向我們本機(jī)。訪問結(jié)果如圖所示:

我們可以看到服務(wù)器成功設(shè)置了Cookie。然后我們?cè)倏纯赐蛳?,異步?qǐng)求能不能帶上Cookie,代碼如下:

后端代碼:

1
2
3
4
5
6
7
8
9
10
@RequestMapping('getCookie')
public String getCookie(HttpServletRequest request,HttpServletResponse response){
    Cookie[] cookies = request.getCookies();
    if (cookies != null && cookies.length >0) {
        for (Cookie cookie : cookies) {
            System.out.println('name:' cookie.getName() '-----value:' cookie.getValue());
        }
    }
    return 'success';
}

前端代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <title>user</title>
    <script src='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js'></script>
    <script>
        $(function () {
            $.ajax({
                url : 'http://www.b.com:8888/test/getCookie',
                method: 'get',
                success : function (json) {
                    console.log(json);
                }
            });
        })
    </script>
</head>
<body>
</body>
</html>

訪問結(jié)果如圖所示:

再看看后臺(tái)打印的日志:

1
name:test-----value:same

同域下,異步請(qǐng)求時(shí),Cookie也能帶到服務(wù)端。

所以,我們?cè)谧銮昂蠖朔蛛x時(shí),前端和后端部署在同一域下,滿足瀏覽器的同源策略,登錄不需要做特殊的處理。

四、不同域下的前后端分離

不同域下,我們的響應(yīng)(Response)能不能設(shè)置Cookie呢?請(qǐng)求時(shí)能不能帶上Cookie呢?我們實(shí)驗(yàn)結(jié)果如下,這里就不給大家貼代碼了。

由于我們?cè)赼.com域下的頁面跨域訪問b.com的服務(wù),b.com的服務(wù)不能設(shè)置Cookie。

如果b.com域下有Cookie,我們?cè)赼.com域下的頁面跨域訪問b.com的服務(wù),能不能把b.com的Cookie帶上嗎?答案是也帶不上。那么我們?cè)趺唇鉀Q 跨域問題呢?

4.1 JSONP解決跨域

JSONP的原理我們可以在維基百科上查看,上面寫的很清楚,我們不做過多的介紹。我們改造接口, 在每個(gè)接口上增加callback參數(shù):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RequestMapping('setCookie')
public String setCookie(HttpServletResponse response,String callback){
    Cookie cookie = new Cookie('test','same');
    cookie.setPath('/');
    response.addCookie(cookie);
    if (StringUtils.isNotBlank(callback)){
        return callback '('success')';
    }
    return 'success';
}
@RequestMapping('getCookie')
public String getCookie(HttpServletRequest request,HttpServletResponse response,String callback){
    Cookie[] cookies = request.getCookies();
    if (cookies != null && cookies.length >0) {
        for (Cookie cookie : cookies) {
            System.out.println('name:' cookie.getName() '-----value:' cookie.getValue());
        }
    }
    if (StringUtils.isNotBlank(callback)){
        return callback '('success')';
    }
    return 'success';
}

如果callback參數(shù)不為空,將返回js函數(shù)。前端改造如下:

設(shè)置Cookie頁面改造如下:

1
2
3
4
5
6
7
8
9
10
11
12
<script>
    $(function () {
        $.ajax({
            url : 'http://www.b.com:8888/test/setCookie?callback=?',
            method: 'get',
            dataType : 'jsonp',
            success : function (json) {
                console.log(json);
            }
        });
    })
</script>

請(qǐng)求Cookie時(shí)改造如下:

1
2
3
4
5
6
7
8
9
10
11
12
<script>
    $(function () {
        $.ajax({
            url : 'http://www.b.com:8888/test/getCookie?callback=?',
            method: 'get',
            dataType : 'jsonp',
            success : function (json) {
                console.log(json);
            }
        });
    })
</script>

所有的請(qǐng)求都加了callback參數(shù),請(qǐng)求的結(jié)果如下:

很神奇吧!我們?cè)O(shè)置了b.com域下的Cookie。 如果想知道為什么?還是看一看JSONP的原理吧。我們?cè)僭L問第二個(gè)頁面,看看Cookie能不能 傳到服務(wù)。后臺(tái)打印日志為:

1
name:test-----value:same

好了,不同域下的前后端分離,可以通過JSONP跨域,從而保持登錄狀態(tài)。 但是,jsonp本身沒有跨域安全規(guī)范,一般都是后端進(jìn)行安全限制, 處理不當(dāng)很容易造成安全問題。

4.2 CORS解決跨域

CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱是”跨域資源共享”(Cross-origin resource sharing)。CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。 整個(gè)CORS通信過程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。 瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺。 如果想要詳細(xì)理解原理,請(qǐng)參考維基百科

CORS請(qǐng)求默認(rèn)不發(fā)送Cookie和HTTP認(rèn)證信息。若要發(fā)送Cookie,瀏覽器和服務(wù)端都要做設(shè)置,咱們要解決的是跨域后的登錄問題,所以要允許跨域發(fā)送 Cookie。

后端要設(shè)置允許跨域請(qǐng)求的域允許設(shè)置和接受Cookie。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RequestMapping('setCookie')
@CrossOrigin(origins='http://www.a.com:8888',allowCredentials = 'true')
public String setCookie(HttpServletResponse response){
    Cookie cookie = new Cookie('test','same');
    cookie.setPath('/');
    response.addCookie(cookie);
    return 'success';
}
@RequestMapping('getCookie')
@CrossOrigin(origins='http://www.a.com:8888',allowCredentials = 'true')
public String getCookie(HttpServletRequest request,HttpServletResponse response){
    Cookie[] cookies = request.getCookies();
    if (cookies != null && cookies.length >0) {
        for (Cookie cookie : cookies) {
            System.out.println('name:' cookie.getName() '-----value:' cookie.getValue());
        }
    }
    return 'success';
}

我們通過@CrossOrigin注解允許跨域,origins設(shè)置了允許跨域請(qǐng)求的域,allowCredentials允許設(shè)置和接受Cookie。

前端要設(shè)置允許發(fā)送和接受Cookie。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<script>
    $(function () {
        $.ajax({
            url : 'http://www.b.com:8888/test/setCookie',
            method: 'get',
            success : function (json) {
                console.log(json);
            },
            xhrFields: {
                withCredentials: true
            }
        });
    })
</script>
<script>
    $(function () {
        $.ajax({
            url : 'http://www.b.com:8888/test/getCookie',
            method: 'get',
            success : function (json) {
                console.log(json);
            },
            xhrFields: {
                withCredentials: true
            }
        });
    })
</script>

我們?cè)L問頁面看一下效果。

沒有Cookie嗎?別急,我們?cè)購臑g覽器的設(shè)置里看一下。

有Cookie了,我們?cè)倏纯丛L問能不能帶上Cookie,后臺(tái)打印結(jié)果如下:

1
name:test-----value:same

我們使用CORS,也解決了跨域。

總結(jié)

前后端分離,基于Cookie-Session機(jī)制的登錄總結(jié)如下

  • 前后端同域——與普通登錄沒有區(qū)別
  • 前后端不同域
    • JSONP方式實(shí)現(xiàn)
    • CORS方式實(shí)現(xiàn)
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
同源策略——瀏覽器的安全衛(wèi)士
使用javascript操作cookie
京東SSO單點(diǎn)登陸實(shí)現(xiàn)分析
什么是跨域,為什么會(huì)有跨域問題的出現(xiàn)
說說JSON和JSONP,也許你會(huì)豁然開朗
JS學(xué)習(xí)35:js使用JSONP、VAR實(shí)現(xiàn)前端跨域
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服