状态保持与身份认证
1. 關(guān)系
1.1 緩存
Cookie和Session
提示:
Cookie和Session是Django程序中用來緩存數(shù)據(jù)的
狀態(tài)保持和Cookie、Session的關(guān)系
提示:
* 容易出現(xiàn)的誤解:狀態(tài)保持就是Cookie和Session,Cookie和Session就是狀態(tài)保持。
* 狀態(tài)保持和Cookie、Session是兩種不同的概念,需要區(qū)分開,不能混淆。
狀態(tài)保持:
Cookie、Session:
* Cookie、Session僅僅是Django提供的緩存機制而已,用于緩存數(shù)據(jù)的。 * 比如:* Cookie和Session緩存購物車數(shù)據(jù)* Cookie和Session緩存用戶登錄狀態(tài) (狀態(tài)保持)狀態(tài)保持和Cookie、Session的關(guān)系
* Cookie和Session僅僅是狀態(tài)保持的一種實現(xiàn)方式而已 * 而能夠?qū)崿F(xiàn)狀態(tài)保持的方式不僅僅只有Cookie和Session,比如JWT也可以實現(xiàn)狀態(tài)保持1.2 應(yīng)用場景
1.1 登錄接口實現(xiàn)的業(yè)務(wù)邏輯
在整個登錄接口實現(xiàn)中,除了檢查用戶名和密碼以外,我們需要通過某種方式來記住用戶身份(狀態(tài)保持),還有用戶認證。
1.2 用戶下次訪問不用登錄
例如,在我們登錄boss直聘網(wǎng)站后,我們可以不用再次登錄就可以直接使用網(wǎng)站,并且網(wǎng)站上有我們的信息
2. cookie
2.1 簡介
需求:
- HTTP協(xié)議本身是無狀態(tài)的,即服務(wù)器無法判斷用戶身份。
問題:
服務(wù)器默認是無法識別當前登錄用戶是誰的,即無法記住登錄狀態(tài)。
解決:
- Cookie
- 我們可以使用Cookie機制記住用戶的登錄狀態(tài)
1. 定義
- Cookie,最早是網(wǎng)景公司的前雇員 Lou Montulli 在 1993 年 3 月發(fā)明的。
- Cookie,指某些網(wǎng)站為了辨別用戶身份、進行session跟蹤而儲存在用戶本地終端上的數(shù)據(jù)(通常經(jīng)過加密)。
- cookie 是一個實際存在的東西,是http協(xié)議中定義header中的字段,實際上是一小段存儲在用戶瀏覽器中的文本信息。
2. 具體位置
- 在瀏覽器左上角的感嘆號或者鎖
- 在檢查模式的Application中的Storage里,其中LocalStorage存儲永久cookie,SessionStorage存儲臨時cookie
2.2 機制
- 客戶端向服務(wù)器發(fā)起請求,如果服務(wù)器需要記錄該用戶狀態(tài),就通過響應(yīng)向客戶端瀏覽器頒發(fā)一個Cookie。
- 該Cookie中需要包含用戶的唯一標識信息
- 客戶端瀏覽器會把Cookie保存起來。
- 當瀏覽器再次請求該網(wǎng)站時,瀏覽器把請求的網(wǎng)址連同該Cookie一同提交給服務(wù)器。
- 服務(wù)器檢查該Cookie,以此來辨認用戶狀態(tài)。
2.3 特點
- Cookie,以鍵值對Key-Value形式進行信息的存儲
- Cookie,基于域名安全,不同域名的Cookie是不能互相訪問的
- 例如: 保存在www.baidu.com域名下面的Cookie是不能被其他域名訪問的
- Cookie,它會自動跟隨當前的請求傳遞到對應(yīng)域名所在的服務(wù)器中。
2.4 操作
1. 設(shè)置Cookie
- 可以通過**HttpResponse()**對象中的set_cookie()方法來設(shè)置Cookie。
- 響應(yīng)對象:常見的構(gòu)造響應(yīng)對象的方式
- HttpResponse():響應(yīng)多種數(shù)據(jù)類型
- JsonResponse():響應(yīng)JSON
- redirect():重定向
- render():渲染并響應(yīng)HTML模板
- max_age:單位為秒,默認為None。
- 如果是臨時Cookie,可將max_age設(shè)置為None。
- 如果是有具體有效期的Cookie,可將max_age設(shè)置為具體的秒數(shù)。
2. 讀取Cookie
- 可以通過HttpRequest對象的COOKIES屬性來讀取本次請求攜帶的cookie值。
3. session
3.1 簡介
需求:
Cookie中存儲敏感信息是否安全?
結(jié)論:
如果存儲前做加密處理,就會是安全的,但是加密后的敏感信息依然會暴露在瀏覽器中
思考:
有沒有一種方式可以將某些敏感數(shù)據(jù)存儲的更加安全些,即加密又不會暴露出去?
解決:
- Session
1. 定義
- 原來session是會話的英文,是一個抽象概念,是開發(fā)者為了實現(xiàn)中斷和繼續(xù)等操作,將usergent和server之間一對一的交互,抽象為“會話狀態(tài)”。
- 現(xiàn)在的session是為了繞開cookie本身和后端存儲實現(xiàn)的一種更高級的會話狀態(tài)實現(xiàn),概念上cookie和session可以認為是同一層次的概念,也可以是不同層次的概念,具體到實現(xiàn)上session存在是因為sessionID的存在,通常要借助cookie實現(xiàn),但這并非必要,只能說是通用性較好的一種實現(xiàn)方案
- 也可以cookie看做一對鍵值對,cookie是session的key,有cookie里的sessionID才能取到用戶信息
- Session,是一種會話控制方式。由服務(wù)端創(chuàng)建,并且保存在服務(wù)端的數(shù)據(jù)存儲形式。
- Session,內(nèi)部也是以key-value 鍵值對的形式存儲數(shù)據(jù)。
- Session,有些內(nèi)容會被加密,所以可以存儲敏感信息。
- 處理Session數(shù)據(jù)的子應(yīng)用:
處理Session的中間件:
PS:如需禁用Session,將上圖中的session中間件注釋掉即可。
3.2 機制
- 客戶端向服務(wù)器發(fā)起請求,如果服務(wù)器需要記錄該用戶狀態(tài),就可以通過Session在服務(wù)端將該用戶的唯一標識信息存儲起來。
- session_key:一個隨機的唯一的不重復的字符串
- session_data:用戶的唯一標識信息(密文)
- 然后,服務(wù)端會向客戶端瀏覽器頒發(fā)一個Cookie。
- 該Cookie中包含了Session存儲數(shù)據(jù)時使用的那個session_key
該Cookie的具體形式為:'sessionid': 'session_key'
- 該Cookie中包含了Session存儲數(shù)據(jù)時使用的那個session_key
- 當瀏覽器再次請求該網(wǎng)站時,瀏覽器把請求的網(wǎng)址連同該Cookie一同提交給服務(wù)器。
- 服務(wù)器提取該Cookie中的session_key,再使用它提取session_data。
- 最后使用session_data來辨認用戶狀態(tài)
3.3 特點
- 存儲敏感、重要的信息
- 因為session數(shù)據(jù)是存儲在服務(wù)端的,不會直接暴露給用戶
- 相比較Cookie可以存儲更多的內(nèi)容
- 不同的瀏覽器,對Cookie都有不同的數(shù)量和大小的限制
- 依賴于Cookie
- 因為session_key需要存儲在Cookie中
- Session共享
- 利用獨立部署的session服務(wù)器(集群)統(tǒng)一管理Session,服務(wù)器每次讀寫Session時,都訪問Session服務(wù)器。
3.4 cookie和session關(guān)系
- 注意:
- 但是兩個獨立的東西,即sessionID雖然存儲在cookie中,但絕不依賴cookie
- 綜合考慮
- 把重要信息存儲在session,用戶名和sessionID可以放在cookie中
- 利用時效機制,給cookie設(shè)置有效期,比如十四天,然后讓用戶十四天再登錄
- 可以設(shè)置sesssionID傳入方式,若有其他方式傳入sessinID,cookie完全可以禁用
3.5 操作
1. 設(shè)置Session
可以通過 HttpRequest() 對象中的session屬性來設(shè)置Session。
request.session['key'] = value class BooksView(View):"""測試模板http://127.0.0.1:8000/books/"""def get(self, request):# 查詢所有圖書信息books = BookInfo.objects.all()# 構(gòu)造上下文context = {'books': books}# 使用上下文渲染'book.html',并返回給客戶端response = render(request, 'books.html', context)# 設(shè)置Cookieresponse.set_cookie('name', 'itcast', max_age=3600)# 設(shè)置Sessionrequest.session['name'] = 'itcast'# 響應(yīng)結(jié)果,并寫Cookie到瀏覽器return response2. 讀取Session
根據(jù)鍵讀取值
request.session.get('key', 默認值) class TestSessionView(View):"""測試Sessionhttp://127.0.0.1:8000/session/"""def get(self, request):# 讀取Sessionname = request.session.get('name')print(name)return http.HttpResponse('測試Session')3. 操作Session的其他方式
清除所有Session,在存儲中刪除值部分。
request.session.clear()清除session數(shù)據(jù),在存儲中刪除session的整條數(shù)據(jù)。
request.session.flush()刪除session中的指定鍵及值,在存儲中只刪除某個鍵及對應(yīng)的值。
del request.session['key']設(shè)置session的有效期
request.session.set_expiry(value)- 如果value是一個整數(shù),session將在value秒沒有活動后過期。
- 如果value為0,那么用戶session的Cookie將在用戶的瀏覽器關(guān)閉時過期。
- 如果value為None,那么session有效期將采用系統(tǒng)默認值,默認為兩周。
- 可以通過在settings.py中設(shè)置SESSION_COOKIE_AGE來設(shè)置全局默認值。
3.6 Session數(shù)據(jù)存儲的位置
1. 默認的存儲位置
Session數(shù)據(jù)默認存儲的位置是在settings.py的DATABASES配置項指定的SQL數(shù)據(jù)庫中
- 因為Session引擎默認的配置為:
-
數(shù)據(jù)庫中的表如圖所示
-
表結(jié)構(gòu)如下
由表結(jié)構(gòu)可知,操作Session包括三個數(shù)據(jù):鍵,值,過期時間。
2. 本地緩存
存儲在本機內(nèi)存中,如果丟失則不能找回,比數(shù)據(jù)庫的方式讀寫更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'3. 混合存儲
優(yōu)先從本機內(nèi)存中存取,如果沒有則從數(shù)據(jù)庫中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'4. Redis
在Redis中保存Session,需要引入第三方擴展,我們可以使用django-redis來解決。
1)安裝擴展
pip install django-redis2)配置
在settings.py文件中做如下設(shè)置
CACHES = {"default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://127.0.0.1:6379/1","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient",}} } SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default"3. JWT
3.1 JWT簡介
1. Json Web Token(JWT)
- JSON Web Token(JWT)是一個非常輕巧的規(guī)范。這個規(guī)范允許我們使用JWT在兩個組織之間傳遞安全可靠的信息。
官方定義:JSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties
JWT是一個有著簡單的統(tǒng)一表達形式的字符串:
2. JWT組成/token格式
- JWT組成,也可以說是token格式,是有header,payload,signature三部分以點分割的字符串
- jwt技術(shù)特性
單點登錄
客戶端在某一臺服務(wù)器(授權(quán)中心)完成登錄授權(quán),拿到token之后,可以憑借token(令牌)在任意其他服務(wù)器中完成身份驗證;
2.1 頭部(Header)
頭部用于描述關(guān)于該JWT的最基本的信息,例如其類型以及簽名所用的算法等。
- JSON內(nèi)容要經(jīng)Base64 編碼生成字符串成為Header。
- 頭部(header):typ(類型說明)和alg(加密方法)
作用:轉(zhuǎn)化:
2.2 載荷(PayLoad)
payload的五個字段都是由JWT的標準所定義的。
1. iss: 該JWT的簽發(fā)者
2. sub: 該JWT所面向的用戶
3. aud: 接收該JWT的一方
4. exp(expires): 什么時候過期,這里是一個Unix時間戳
5. iat(issued at): 在什么時候簽發(fā)的
- JSON內(nèi)容要經(jīng)Base64 編碼生成字符串成為PayLoad。
作用:存儲用戶信息
payload = json.dumps(payload) payload = base64.b64encode.encode().decode() print("payload:", payload)2.3 簽名(signature)
- 這個部分header與payload通過header中聲明的加密方式,使用密鑰secret進行加密,生成簽名。 JWS的主要目的是保證了數(shù)據(jù)在傳輸過程中不被修改,驗證數(shù)據(jù)的完整性。但由于僅采用Base64對消息內(nèi)容編碼,因此不保證數(shù)據(jù)的不可泄露性。所以不適合用于傳輸敏感數(shù)據(jù)。
作用:校驗token真?zhèn)?/p>
使用哈希算法對信息進行摘要生成簽名,目的是保證信息的可靠性;
原理:只要信息沒有改動,那么原信息和簽名是匹配的
3、token簽發(fā)
簽發(fā)
import hmac, hashlib # hmac:Python的一個用于hash(簽名,散列)運算的模塊 hashlib:專門實現(xiàn)具體的算法# 1、構(gòu)建哈希對象 # key: 加密使用的秘鑰--生成簽名 # msg: header和payload信息 # digestmod: 算法 key = "eerewrwerwrwewrwegegsf" SECRET_KEY = '' message = header + '.' + payload h_obj = hmac.new(key = SECRET_KEY.encode(), msg=message.encode(), djgestmod=hashlib.sha256) # 2、找對象里的方法,生成簽名 signature = b_obj.hexdigest() print("signature:", signature) ======================= JWT_TOKEN = header + '.' + signature print("token",JWT_TOKEN) =======================4、token校驗
核心原理:重新對header和payload按照簽發(fā)時相同的秘鑰和算法加密
# 模擬前端傳參 token_from_browser = JWT_TOKEN # 有效 token_from_browser = 'fdds' + JWT_TOKEN # 篡改# 模擬校驗原理 # 原理:只要信息沒有改動,那么原信息和簽名是匹配的 # 只要信息沒有被篡改,那么根據(jù)相同而秘鑰和算法,生成的第三部分簽名和原來的簽名一定一致# 1、獲取信息(header和payload) old_header = token_from_browser.split('.',[0]) old_payload = token_from_brower.split('.',[1]) old_signature = token_from_brower.split('.'[2]) # 2、把信息按照相同的秘鑰和算法,重新生成新的簽名 message = old_header + '.' +old_payload new_h_obj = hmac.new(key=SECRET.KEY.encode(), msg=message.encode(), digestmod=hashlib.sha256) new_signature = new_h_obj.hexdigest() print("新的簽名:", new_signature) # 3、比對新舊簽名是否一致:一致則信息沒有被篡改,否則信息就被篡改了 if old_signature = new_signature:print("驗證成功")# 提取用戶數(shù)據(jù)user_json = base64.b64decode(old_payload.encode().decode())user_dict = json.loads(user_json)print("解析出來的用戶身份信息:", user_dict) else:print("驗證失敗")4. PythonLib
4.1 JWT的Python庫
- 獨立的JWT Python庫
- itsdangerous
- JSONWebSignatureSerializer
- TimedJSONWebSignatureSerializer (可設(shè)置有效期)
- pyjwt
https://pyjwt.readthedocs.io/en/latest/
4.2 安裝
$ pip install pyjwt4.3 用例
>>> import jwt>>> encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256')>>> encoded_jwt'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'>>> jwt.decode(encoded_jwt, 'secret', algorithms=['HS256']){'some': 'payload'} import jwt from flask import current_appdef generate_jwt(payload, expiry, secret=None):"""生成jwt:param payload: dict 載荷:param expiry: datetime 有效期:param secret: 密鑰:return: jwt"""_payload = {'exp': expiry}_payload.update(payload)if not secret:secret = current_app.config['JWT_SECRET']token = jwt.encode(_payload, secret, algorithm='HS256')return token.decode()def verify_jwt(token, secret=None):"""檢驗jwt:param token: jwt:param secret: 密鑰:return: dict: payload"""if not secret:secret = current_app.config['JWT_SECRET']try:payload = jwt.decode(token, secret, algorithm=['HS256'])except jwt.PyJWTError:payload = Nonereturn payload5. 實施方案
5.1 需求
- 設(shè)置有效期,但有效期不宜過長,需要刷新。如何解決刷新問題?
- 手機號+驗證碼(或帳號+密碼)驗證后頒發(fā)接口調(diào)用token與refresh_token(刷新token)
- Token 有效期為2小時,在調(diào)用接口時攜帶,每2小時刷新一次
- 提供refresh_token,refresh_token 有效期14天
- 在接口調(diào)用token過期后憑借refresh_token 獲取新token
- 未攜帶token 、錯誤的token或接口調(diào)用token過期,返回401狀態(tài)碼
- refresh_token 過期返回403狀態(tài)碼,前端在使用refresh_token請求新token時遇到403狀態(tài)碼則進入用戶登錄界面從新認證。
- token的攜帶方式是在請求頭中使用如下格式:
- 注意:Bearer前綴與token中間有一個空格
5.2 實現(xiàn)
1. 注冊或登錄獲取token
# toutiao/resources/user/passport.pty class AuthorizationResource(Resource):"""認證"""def _generate_tokens(self, user_id, with_refresh_token=True):"""生成token 和refresh_token:param user_id: 用戶id:return: token, refresh_token"""# 頒發(fā)JWTnow = datetime.utcnow()expiry = now + timedelta(hours=current_app.config['JWT_EXPIRY_HOURS'])token = generate_jwt({'user_id': user_id, 'refresh': False}, expiry)refresh_token = Noneif with_refresh_token:refresh_expiry = now + timedelta(days=current_app.config['JWT_REFRESH_DAYS'])refresh_token = generate_jwt({'user_id': user_id, 'refresh': True}, refresh_expiry)return token, refresh_tokendef post(self):"""登錄創(chuàng)建token"""json_parser = RequestParser()json_parser.add_argument('mobile', type=parser.mobile, required=True, location='json')json_parser.add_argument('code', type=parser.regex(r'^\d{6}$'), required=True, location='json')args = json_parser.parse_args()mobile = args.mobilecode = args.code# 從redis中獲取驗證碼key = 'app:code:{}'.format(mobile)try:real_code = current_app.redis_master.get(key)except ConnectionError as e:current_app.logger.error(e)real_code = current_app.redis_slave.get(key)try:current_app.redis_master.delete(key)except ConnectionError as e:current_app.logger.error(e)if not real_code or real_code.decode() != code:return {'message': 'Invalid code.'}, 400# 查詢或保存用戶user = User.query.filter_by(mobile=mobile).first()if user is None:# 用戶不存在,注冊用戶user_id = current_app.id_worker.get_id()user = User(id=user_id, mobile=mobile, name=mobile, last_login=datetime.now())db.session.add(user)profile = UserProfile(id=user.id)db.session.add(profile)db.session.commit()else:if user.status == User.STATUS.DISABLE:return {'message': 'Invalid user.'}, 403token, refresh_token = self._generate_tokens(user.id)return {'token': token, 'refresh_token': refresh_token}, 2012. 請求鉤子
# common/utils/middlewares.py from flask import request, g from .jwt_util import verify_jwtdef jwt_authentication():"""根據(jù)jwt驗證用戶身份"""g.user_id = Noneg.is_refresh_token = Falseauthorization = request.headers.get('Authorization')if authorization and authorization.startswith('Bearer '):token = authorization.strip()[7:]payload = verify_jwt(token)if payload:g.user_id = payload.get('user_id')g.is_refresh_token = payload.get('refresh')3. 強制登錄裝飾器
# common/utils/decorators.py def login_required(func):"""用戶必須登錄裝飾器使用方法:放在method_decorators中"""@wraps(func)def wrapper(*args, **kwargs):if not g.user_id:return {'message': 'User must be authorized.'}, 401elif g.is_refresh_token:return {'message': 'Do not use refresh token.'}, 403else:return func(*args, **kwargs)return wrapper4. 更新token接口
# toutiao/resources/user/passport.py class AuthorizationResource(Resource):"""認證"""...# 補充put方式 更新token接口def put(self):"""刷新token"""user_id = g.user_idif user_id and g.is_refresh_token:token, refresh_token = self._generate_tokens(user_id, with_refresh_token=False)return {'token': token}, 201else:return {'message': 'Wrong refresh token.'}, 4036. 禁用問題
6.1 需求
- token頒發(fā)給用戶后,在有效期內(nèi)服務(wù)端都會認可,但是如果在token的有效期內(nèi)需要讓token失效,該怎么辦?
- 此問題的應(yīng)用場景:
- 用戶修改密碼,需要頒發(fā)新的token,禁用還在有效期內(nèi)的老token
- 后臺封禁用戶
- 偽代碼思路如下:
在redis中使用set類型保存新生成的token
- 客戶端使用token進行請求時,如果驗證token通過,則從redis中判斷是否存在該用戶的user:{}:token記錄:
- 若不存在記錄,放行,進入視圖進行業(yè)務(wù)處理
- 若存在,則對比本次請求的token是否在redis保存的set中:
- 若存在,則放行
- 若不在set的數(shù)值中,則返回403狀態(tài)碼,不再處理業(yè)務(wù)邏輯
說明:
1. redis記錄設(shè)置有效期的時長是一個token的有效期,保證舊token過期后,redis的記錄也能自動清除,不占用空間。
2. 使用set保存新token的原因是,考慮到用戶可能在舊token的有效期內(nèi),在其他多個設(shè)備進行了登錄,需要生成多個新token,這些新token都要保存下來,既保證新token都能正常登錄,又能保證舊token被禁用
6.2 具體代碼實現(xiàn)
1. 修改密碼接口
class ModifyPasswordResource(Resource):# 修改密碼要求用戶必須登錄method_decorators = [login_required]def post(self):"""修改密碼邏輯"""# 1.獲取用戶iduser_id = g.user_id# 2.保存到redis中的keykey = 'user:{}:token'.format(user_id)# 3.獲取管道對象pl = current_app.redis_master.pipeline()# 4.先刪除已有的白名單if pl.exists(key):pl.delete(key)# 5.生成新的token值new_token, refresh_token = self._generate_tokens(user_id)# 6.sadd 往集合中添加成員--添加修改密碼后的新的token值pl.sadd(key, new_token)# 7.設(shè)置2小時有效期pl.expire(key, 7200)# 8.設(shè)置修改密碼的標志位,同時設(shè)置2小時有效期modify_key = "modify:{}".format(user_id)pl.setex(modify_key, 7200, "modify")# 9.執(zhí)行管道pl.execute()# 10.修改密碼成功,并返回新的token值return {"message": "修改密碼成功", "valid_token": new_token}2. 在middleware 的def jwt_authorization():方法中補充驗證白名單的邏輯
def jwt_authorization():"""每次請求之前進行jwt驗證:return:"""# 請求頭Header攜帶# {Authorization: "Bearer jwt_token"}# 默認值g.user_id = Noneg.is_refresh = False# 1.提取請求頭中的token數(shù)據(jù)header_token = request.headers.get("Authorization")# 2.截取真正的jwt-token值if header_token is not None and header_token.startswith("Bearer "):jwt_token = header_token[7:]# 3.jwttoken的校驗 --- 如果token沒有值 或者過期了 自動會拋出401異常payload = verify_jwt(token=jwt_token)# 4.獲取載荷中的用戶信息,使用g對象存儲用戶信息if payload is not None:g.user_id = payload.get("user_id")g.is_refresh = payload.get("is_refresh", False)# ========================【白名單驗證邏輯】================================if g.user_id:# 根據(jù)key獲取是否進行過密碼修改的標志位modify_key = "modify:{}".format(g.user_id)modify = current_app.redis_master.get(modify_key)# 如果是修改過密碼,同時又不是刷新token,需要進行白名單認證if modify == 'modify' and g.is_refresh is False:# 白名單認證ret = white_list()# 如果認證結(jié)果為False 代表token沒有在白名單內(nèi)部if ret is False:return "token is not in white list", 4033. 判斷用戶上傳的token是否在白名單列表中
def white_list():"""判斷用戶上傳的token是否在白名單列表中如果在:正常訪問如果不在:攔截不讓訪問視圖函數(shù),需要使用修改密碼后生成的最新的token才能訪問:return: BooL值 False代表token沒有在白名單內(nèi)部"""# 用戶iduser_id = g.user_idkey = 'user:{}:token'.format(user_id)# 獲取白名單內(nèi)部的token# smembers 獲取集合中的成員valid_tokens = current_app.redis_master.smembers(key)# set類型數(shù)據(jù) 裝的bytes類型數(shù)據(jù)print(type(valid_tokens))# 把set、轉(zhuǎn)換成python的列表valid_tokens = list(valid_tokens)# 提取前端發(fā)送的tokenheader_token = request.headers.get("Authorization")token = header_token[7:]# 判斷前端發(fā)送的token值是否在白名單列表中,如果不在返回403 重新登錄if valid_tokens and token not in valid_tokens:return Falseelse:return True6.3 思路流程圖
總結(jié)
- 上一篇: 双因子身份认证如何保障 Windows
- 下一篇: 【算法分析与设计】平面最近点对(含最近距