Django用戶組及登錄、注冊、注銷、JWT

1. 用戶模型創建

通常來說既然用了django了,不會完全舍棄它的用戶模型吧,區別就是繼承類的深度。

1.1 User

直接用django自帶的User模型,如果你能夠把需求砍到這種層度,沒毛病。

1.2 AbstractUser

這一層幫你創建好了一些字段:

password, last_login, username, first_name, last_name, email, is_staff, is_active, date_joined

其中is_staff是能訪問admin的權限。
還有幾個基礎方法。
其實繼承這層一般就可以了,再新建幾列諸如手機號,頭像之類的,美滋滋。

1.3 AbstractBaseUser

更深一層的繼承
只包含
password, last_login
但是封裝了password的加密生成,一些狀態的判斷……
這是能繼承的最基礎的類了,如果還想更深的話,可能只能重寫了

最后別忘了重新指定一下用戶模型
AUTH_USER_MODEL = 'account.Account'

2. 用戶模型獲取
2.1 獲取用戶
from django.contrib.auth import get_user_model

User = get_user_model()
獲取
User.objects.get/filter
創建
User.objects.create(username="xx")
設置密碼
user = User.objects.get(xx)
user.set_password("xxxxx")
2.2 分組
from django.contrib.auth.models import Group
Group.objects.create(name="試用用戶組")
group = Group.objects.get(name="試用用戶組")
組內所有用戶:
users = group.user_set.all()
用戶加入組:
user = User.objects.get(xx)
user.groups.add(demo_group)

我這里的接口使用了django-restframework,接下來的操作先封裝好一些類

from rest_framework.views import APIView
from rest_framework import permissions
from rest_framework_jwt.authentication import JSONWebTokenAuthentication


class BaseAPIView(APIView):
    permission_classes = (permissions.AllowAny, )
    authentication_classes = (JSONWebTokenAuthentication, )
3. 注冊
3.1 表單

目前第一版暫不需要密碼,通過手機短信注冊。

from rest_framework import serializers

class RegisterSerializer(serializers.Serializer):
    mobile_phone = serializers.IntegerField(allow_null=False)
    verification_code = serializers.IntegerField()
    name = serializers.CharField()
    company = serializers.CharField()
3.2 控制層

寫一下整體邏輯


class Register(APIView):
    serializer_class = RegisterSerializer

    def post(self, request, format=None):
        serializer = RegisterSerializer(data=request.data)
        if not serializer.is_valid():
            return render_no_match_v2(serializer.errors)

        mobile_phone = serializer.data["mobile_phone"]
        ...
        item = generate_Register_item(mobile_phone, verification_code, name, company)
        return render_api_item_v2({"item": item})
3.3 服務層

整體的流程大概如圖:

register.jpg

這邊我們進行的是途中的api2,api1我沒有寫在上面,是一個請求短信服務商發送短信通知的接口。
需要注意的地方有一處:服務器端要保存下來請求的驗證碼與api2里用戶輸入的驗證碼匹配
當然還要考慮覆蓋(比如說用戶請求了兩次),以及這個存儲的過期時間
綜上,感覺用Redis是比較合適的。
不過,Emmmm,人手不足,怕出了問題的時候沒人有時間去維護,這里先用django的cache了cache.set(key, value, timeout=30*60)
注:區別在于cache會隨著django的重啟而清空
接下來是注冊(api2)的service層:

def generate_Register_item(mobile_phone, verification_code, name, company):
    vc = cache.get(mobile_phone)
    if vc and verification_code != vc:
        return "驗證碼錯誤"
    User = get_user_model()
    if User.objects.filter(telephone=mobile_phone):
        return "該手機已注冊"
    user = User.objects.create(telephone=mobile_phone, username=mobile_phone)
    user.real_name = name
    user.company = company
    user.save()
    cache.delete(mobile_phone)
    return "注冊成功"
4. 登錄
4.1 表單

同樣,沒有設置密碼,采用短信服務登錄

4.2 控制層

基本如上

4.3 服務層

django是定制了login方法的
from django.contrib.auth import login
接受三個參數login(request, user, backend=None)
本質上應該是往session里寫入了一個hash值來保存登錄狀態。
這里需要注意的是登錄前是需要驗證用戶名密碼的。
密碼在數據庫中通常不是明文存儲,而是加鹽再經過一個不可逆的hash操作存入數據庫。
所以這里的驗證本質上應該是把用戶輸入的明文密碼再經過這樣的加鹽加密,然后對比兩個字符串是否相同(沒深入了解過,個人的理解),不過這里django也有封裝的方法

from django.contrib.auth import authenticate
authenticate(username=xx, password=xx)

不過本次項目里因為暫不考慮密碼,所以不需要這一步驟,直接短信驗證后login
但是會報錯,因為正常的步驟是先authenticate,再login,其中authenticate方法會給user加了一個屬性backend
隨便寫個user測試一下得到這個backend值,賦給user

user.backend='django.contrib.auth.backends.ModelBackend'
5. 注銷

這個就不寫了,跟login一樣,django還有一個logout方法
logout(request)

6. JWT

老樣子,使用一個工具之前先搞明白它的作用,以及它和其它類似工具的區別

6.1 作用

JWT全稱:Json Web Token,一種登錄狀態的令牌驗證機制。

6.2 構成

JWT分為三段,用"."來分隔。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Im1hbmJ1ZyIsIm9yaWdfaWF0IjoxNTE2MzQ5ODYwLCJlbWFpbCI6IiIsImV4cCI6MTUxNjQzNjI2MCwidXNlcl9pZCI6N30.FNOGMZ_c6pD7q6ebhjcblPcQYyVelrV5-XJHLcX_ZQU

第一部分:頭部(header)

{
  'typ': 'JWT',
  'alg': 'HS256'
}
第二部分:載荷(payload)
第三部分:簽證(signature)
其中JWT要在服務端設置好秘鑰,簽證時候和base64后的header,payload共同生成signature
6.3 對比,差異

說到驗證登錄狀態一般都會想到Session,我們先來捋一下一般判斷登錄狀態的流程。

  1. Cookie
    理論上來講,用戶信息可以存到Cookie里的,如果無論你還是服務方都覺得這個安全問題無所謂的話 -.-!
  2. Session
    應該是主流的方法吧,記得前年剛工作時各種面試都會問到這個。大概就是每次登錄時服務端會在數據庫里(或者Redis之類的?)存下一條記錄,然后把session返回給瀏覽器,瀏覽器保存下來,接下來的操作會拿這個session_id向服務器驗證。
    至于Session可能隱藏的問題一個是搞負載均衡時如果沒把Session存到一臺服務器上可能會不斷重新登錄(Emmmmm這個都沒考慮到還是別配多服務器了),再一個就是如果流量很大,對存儲的服務器壓力過大(T.T入行尚淺,還沒經歷過什么大型的項目,這種情況下可能會把Redis也撘成集群?)
  3. JWT
    至于JWT,其實跟Session挺像的,琢磨了好久有什么區別,后來理解大概就是服務端不用存儲吧。
6.4 驗證流程
  1. 客戶端用用戶名和密碼請求服務端,成功后返回token
  2. 客戶端存下token,每次請求時放到頭部authorization里
  3. 服務器收到客戶端請求時先驗證token
6.5 具體實現代碼

同樣,本次項目采用django-restframework
關于具體的代碼,先弄清總共分為三個模塊:生成驗證刷新
其實這個庫可以直接用

from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token, verify_jwt_token

如果有什么特殊的需求那么解決辦法其實也很簡單,比如說一層層依次點開obtain_jwt_token,找一個合適的層次的類繼承它。

舉個栗子:
現在要為網站設計子域名,比如說產品環境叫dev-data.xxx.xxx,預覽版叫dev-preview.xxx.xxx,要為用戶設計個權限控制

那么完全可以先一層層往上找
obtain_jwt_token >>> ObtainJSONWebToken >>> JSONWebTokenAPIView
停,重寫JSONWebTokenAPIView的post方法,加一層用戶組的判斷就ok了

嗯,最后注意一點,別忘了以后的每個api里都加上這個token的驗證,可以重新定義個基類

from rest_framework.views import APIView
from rest_framework import permissions
from rest_framework_jwt.authentication import JSONWebTokenAuthentication


class BaseAPIView(APIView):
    permission_classes = (permissions.AllowAny, )
    authentication_classes = (JSONWebTokenAuthentication, )
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內容