1. 程式人生 > 實用技巧 >spring 中aop 切面實踐

spring 中aop 切面實踐

一 會話跟蹤技術

什麼是會話跟蹤

我們需要先了解一下什麼是會話!可以把會話理解為客戶端與伺服器之間的一次會晤,在一次會晤中可能會包含多次請求和響應。例如你給10086打個電話,你就是客戶端,而10086服務人員就是伺服器了。從雙方接通電話那一刻起,會話就開始了,到某一方結束通話電話表示會話結束。在通話過程中,你會向10086發出多個請求,那麼這多個請求都在一個會話中。
在Web中,客戶向某一伺服器發出第一個請求開始,會話就開始了,直到客戶關閉了瀏覽器會話結束。

在一個會話的多個請求中共享資料,這就是會話跟蹤技術。例如在一個會話中的請求如下:  請求銀行主頁;

  • 請求登入(請求引數是使用者名稱和密碼);
  • 請求轉賬(請求引數與轉賬相關的資料);
  • 請求信譽卡還款(請求引數與還款相關的資料)。

在這上會話中當前使用者資訊必須在這個會話中共享的,因為登入的是張三,那麼在轉賬和還款時一定是相對張三的轉賬和還款!這就說明我們必須在一個會話過程中有共享資料的能力。

會話路徑技術是用Cookie或session完成的

我們知道HTTP協議是無狀態協議,也就是說每個請求都是獨立的!無法記錄前一次請求的狀態。但HTTP協議中可以使用Cookie來完成會話跟蹤!在Web開發中,使用session來完成會話跟蹤,session底層依賴Cookie技術。

二 cookie元件

cookie的由來

大家都知道HTTP協議是無狀態的。

無狀態的意思是每次請求都是獨立的,它的執行情況和結果與前面的請求和之後的請求都無直接關係,它不會受前面的請求響應情況直接影響,也不會直接影響後面的請求響應情況。

就好比使用者登入商城之後購物車新增1,然後傳送新增請求,伺服器記不得你之前的登入狀態所以需要重新提交登入請求,最後才能獲得你的使用者資訊,所以在web應用必須在使用者瀏覽其他商品時保持已經登入的狀態,那麼就需要這一系列新增商品的操作都要在一個會話中保持,多次請求共享一個數據,即在這個會話中就是該使用者傳送多次請求,不必每次請求都需要校驗身份。因此cookie就在這樣一個場景下誕生。

什麼是cookie

其實Cookie是key-value結構,類似於一個python中的字典。隨著伺服器端的響應傳送給客戶端瀏覽器。然後客戶端瀏覽器會把Cookie儲存起來,當下一次再訪問伺服器時把Cookie再發送給伺服器。 Cookie是由伺服器建立,然後通過響應傳送給客戶端的一個鍵值對。客戶端會儲存Cookie,並會標註出Cookie的來源(哪個伺服器的Cookie)。當客戶端向伺服器發出請求時會把所有這個伺服器Cookie包含在請求中傳送給伺服器,這樣伺服器就可以識別客戶端了!

cookie常見的登入案例

  • 首先使用者在客戶端瀏覽器向伺服器首次發起登入請求
  • 登入成功後,服務端會把登入的使用者資訊存在cookie中,並將cookie返回給客戶端瀏覽器
  • 客戶端瀏覽器接收到 cookie 請求後,會把 cookie 儲存到本地(可能是記憶體,也可能是磁碟,看具體使用情況而定)
  • 以後再次訪問該 web 應用時,客戶端瀏覽器就會把本地的 cookie 帶上,這樣服務端就能根據 cookie 獲得使用者資訊了,有了使用者資訊就能訪問該使用者在資料庫中的資料

比如查詢資料與改資料都需要登入認證,如果沒有cookie情況下,登入之後傳送查資料的請求,服務端返回資料給客戶端,這時我需要根據查好的資料進行更改,然後傳送相關請求,因為伺服器是無狀態,它認為你這次請求與上次請求無關,所以這次請求沒有登入認證需要進行登入,然後再返回時可能是你自己設定的重定向的登入頁面了。所以這兩次請求就是兩次會話,是資料隔離的。

如果加上cookie,登入成功之後,就會返回cookie到你的客戶端中,裡面有你的身份標識,然後每一次傳送請求都會帶著這個標識,所以可以在一個會話中傳送多個需要登入認證的請求,且不需要重複的登入,直接通過cookie中的標識在伺服器上得到許可權,那麼在查到資料後,還可以繼續進行改操作,因為這幾個事件都有登入狀態的認證在同一個會話中。

cookie的原理

cookie的工作原理是:由伺服器產生cookie,瀏覽器收到請求後儲存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上Cookie,這樣伺服器就能通過Cookie的內容來判斷這個是“誰”了。

cookie規範

  • Cookie大小上限為4KB;
  • 一個伺服器最多在客戶端瀏覽器上儲存20個Cookie;
  • 一個瀏覽器最多儲存300Cookie;

上面的資料只是HTTP的Cookie規範,但在瀏覽器大戰的今天,一些瀏覽器為了打敗對手,為了展現自己的能力起見,可能對Cookie規範“擴充套件”了一些,例如每個Cookie的大小為8KB,最多可儲存500個Cookie等!但也不會出現把你硬碟佔滿的可能!
注意,不同瀏覽器之間是不共享Cookie的。也就是說在你使用IE訪問伺服器時,伺服器會把Cookie發給IE,然後由IE儲存起來,當你在使用FireFox訪問伺服器時,不可能把IE儲存的Cookie傳送給伺服器。

cookie的覆蓋

如果伺服器端傳送重複的Cookie那麼會覆蓋原有的Cookie,例如客戶端的第一個請求伺服器端傳送的Cookie是:Set-Cookie: a=A;第二請求伺服器端傳送的是:Set-Cookie: a=AA,那麼客戶端只留下一個Cookie,即:a=AA。

在瀏覽器中檢視cookie

瀏覽器中按F12,點network---cookies就能看到

Django中操作cookie

# 新增cookie
def set_cookie(request):
    # 瀏覽器向我這個地址發一個請求,就在瀏覽器寫入 name = arther
    obj = HttpResponse('ok')
    obj.set_cookie('name', 'egon')  # 寫入到瀏覽器了,在http響應頭裡:cookie:name=egon
    obj.set_cookie('age', '18')  # 寫入到瀏覽器了,在http響應頭裡:cookie:age=18
    return obj


'''

Set-Cookie: name=egon; Path=/
Set-Cookie: age=18; Path=/

'''


# 得到cookie

def get_cookie(request):
    # 瀏覽器向我這個地址發一個請求,就在瀏覽器寫入 name = arther
    print(request.COOKIES)
    print(request.COOKIES.get('name'))
    return HttpResponse('我拿了你傳過來的cookies')


# 刪除cookie
def delete_cookie(request):
    obj = HttpResponse('我刪除了你 name 這個cookie')
    obj.delete_cookie('name')
    return obj

引數:

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
  • default: 預設值
  • salt: 加密鹽
  • max_age: 後臺控制過期時間
rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value)
rep.set_signed_cookie(key,value,salt='加密鹽')
  • key, 鍵
  • value='', 值
  • max_age=None, 超時時間 cookie需要延續的時間(以秒為單位)如果引數是\ None`` ,這個cookie會延續到瀏覽器關閉為止
  • expires=None, 超時時間(IE requires expires, so set it if hasn't been already.)
  • path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面訪問,瀏覽器只會把cookie回傳給帶有該路徑的頁面,這樣可以避免將cookie傳給站點中的其他的應用。
  • domain=None, Cookie生效的域名 你可用這個引數來構造一個跨站cookie。如, domain=".example.com"所構造的cookie對下面這些站點都是可讀的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果該引數設定為 None ,cookie只能由設定它的站點讀取
  • secure=False, 瀏覽器將通過HTTPS來回傳cookie
  • httponly=False 只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋)
def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
                   domain=None, secure=False, httponly=False)

# key
# value
# max_age:傳個數字,以秒計,過期時間,有預設值 (6天后過期:60*60*24*5)
---瞭解
# expires:傳時間物件,date=datetime.timedelta()
# path:預設 / 表示當前域下的所有路徑  http://127.0.0.1:8000/lqz/dfd/
# domain:在那個域下有效,比如登入後在當前伺服器的另一個域中沒有登入狀態
# secure:是否Https傳輸cookie
# httponly:cookie只支援http傳輸

Cookie版登陸校驗

# 登陸的檢視函式,成功則返回cookie中帶有'is_login'=True(可以加鹽)
# 之後的請求中cookie帶有'is_login'=True,即可訪問該使用者
def login(request):
    if request.method == 'POST':

        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        print(name)
        all_info = models.Userinfo.objects.all()

        for user_obj in all_info:
            if name == user_obj.name and pwd == user_obj.password:
                import datetime
                now = datetime.datetime.now().strftime('%Y-%m-%d %X')
                print(now)
                obj = JsonResponse({'code': 1, 'info': '登入成功'})
                obj.set_cookie('is_login', True)
                obj.set_cookie('username', name)
                obj.set_cookie('login_time', now)

                return obj
        else:
            flag = {'code': 0, 'info': '登入失敗'}
            return JsonResponse(flag)
          
          
          
# 寫成裝飾器
def login_auth(func):
    def inner(request, *args, **kwargs):
        if request.COOKIES.get('is_login'):
            return func(request, *args, **kwargs)
        else:
            url = reverse('login')
            return redirect(url)

    return inner


三 Session元件

session的由來

cookie雖然在一定程度上解決了'保持狀態'的需求,但是由於cookie本身最大支援4096位元組,以及它本身儲存在客戶端,會被攔截或切取,如上述的登入裝飾器,登入成功後在cookie中設定'is_login'=True來標識一個使用者的身份與許可權。如果有人在本地客戶端竊取登入成功後cookie,然後再次傳送該請求即可盜用該使用者,因此就需要有一種新的東西,它能支援更多的位元組,並且他儲存在伺服器(相對安全,在伺服器不易被竊取),有較高的安全性。這就是Session。

問題來了,基於HTTP協議的無狀態特徵,伺服器根本就不知道訪問者是“誰”。那麼上述的Cookie就起到橋接的作用。

我們可以給每個客戶端的Cookie分配一個唯一的session_id,這樣使用者在訪問時,通過Cookie,伺服器就知道來的人是“誰”。然後我們再根據不同的Cookie的id,在伺服器上儲存一段時間的私密資料,如“賬號密碼”等等。

總結而言:Cookie彌補了HTTP無狀態的不足,讓伺服器知道來的人是“誰”;但是Cookie以文字的形式儲存在本地,自身安全性較差;所以我們就通過Cookie識別不同的使用者,對應的在Session裡儲存私密的資訊以及超過4096位元組的文字。

另外,上述所說的Cookie和Session其實是共通性的東西,不限於語言和框架。

session元件的使用

1.存在於服務端的鍵值對,最終會存在session表中,有id,data,date三個欄位,儲存的資料會以加密的形式如使用者資訊拼接到欄位data下的記錄,然後隨即生成一個字串做為session_id來標識該使用者身份,該id會放在cookie中返回到客戶端的瀏覽器中,然後每次訪問帶上這個cookie就是已經登入的使用者的訪問

2.同一個瀏覽器不允許登入多個賬戶,不同瀏覽器可以登入同一個賬戶

3.session的使用(必須遷移資料)
		-增:request.session['name']=lqz
    -查:request.session['name']
    -改:request.session['name']=egon
    -刪:del request.session['name']
    -設定過期時間:request.session.set_expiry(10)
    
4.session的其他使用
		-request.session.setdefault('k1',111)  # 有該key值則不設定,沒有則設定
  	-request.session.get('name',None)      
    -del request.session['k1']
    
    # 所有 鍵、值、鍵值對
    -request.session.keys()
		-request.session.values()
    -request.session.items()
    
    -request.session.session_key
    # 獲取那個放入cookie中的隨機字串,也是session表中用來標識使用者身份的欄位
    -request.session.exists("session_key")
    # 判斷這個隨機字串有沒有數字
    # 注意在登入過程中還沒有形成session_key,所以此時為None,在登入校驗完後響應瀏覽器返回資料		時經過中介軟體形成的session_key
    
		-request.session.delete()  # 在session表中刪除當前這個登入者的資料,
    -request.session.flush()   # 所以當請求來時cookie中的session_id匹配不上session表的數																 據校驗失敗,需要重新整理將失效cookie設定為過期

四 cgb裝飾器

from django.views import View
from django.utils.decorators import method_decorator
# 使用登入認證裝飾器:多了一個self引數,所以呼叫模組method_decorator
# 用法一
# @method_decorator(login_auth,name='get')
# @method_decorator(login_auth,name='post')
class UserInfo(View):
    # 用法二
    @method_decorator(login_auth)
    def get(self, request, *args, **kwargs):
        return HttpResponse('userinfo get')
    
    
# 總結:兩種用法
	-加在類上:@method_decorator(login_auth,name='get')
  -載入方法上:@method_decorator(login_auth)

五 cookie與session的不同

  • 作用範圍不同,Cookie 儲存在客戶端(瀏覽器),Session 儲存在伺服器端。
  • 存取方式的不同,Cookie 只能儲存 ASCII,Session 可以存任意資料型別,一般情況下我們可以在 Session 中保持一些常用變數資訊,比如說 UserId 等。
  • 有效期不同,Cookie 可設定為長時間保持,比如我們經常使用的預設登入功能,Session 一般失效時間較短,客戶端關閉或者 Session 超時都會失效。
  • 隱私策略不同,Cookie 儲存在客戶端,比較容易遭到不法獲取,早期有人將使用者的登入名和密碼儲存在 Cookie 中導致資訊被竊取;Session 儲存在服務端,安全性相對 Cookie 要好一些。
  • 儲存大小不同, 單個 Cookie 儲存的資料不能超過 4K,Session 可儲存資料遠高於 Cookie。