58.5-登錄功能實(shí)現(xiàn)和認(rèn)證裝飾器

不要妄想事情變得簡單往堡,還是期待自己能做的更好吧!


總結(jié):

  1. 網(wǎng)絡(luò)安全是一個很有前途的方向久信;
  2. session和cookie是解決無狀態(tài)的問題(用戶來了);
  3. 用戶密碼加密不在用戶端加密蝴猪;

用戶功能設(shè)計與實(shí)現(xiàn)

提供用戶注冊處理
  1. 提供用戶登錄處理
  2. 提供路由配置
1. 用戶登錄接口設(shè)計

接收用戶通過POST方法提交的登錄信息调衰,提交的數(shù)據(jù)是JSON格式數(shù)據(jù)
Restful=URL+METHOD URL:/user/reg ; METHOD:POST

從user表中email找出匹配的一條記錄,驗(yàn)證密碼是否正確自阱。
驗(yàn)證通過說明是合法用戶登錄嚎莉,顯示歡迎頁面。
驗(yàn)證失敗返回錯誤狀態(tài)碼沛豌,例如4xx

{
"password":"abc",
"email":"wayne@magedu.com"
}
1.1 路由配置
from django.conf.urls import url
from .views import reg,show,login

urlpatterns = [
    url(r'^reg$',reg),
    url(r'^login$',login),
    url(r'^show$',show),
]
1.2 登錄代碼
from django.http import JsonResponse,HttpRequest,HttpResponseBadRequest
import simplejson,jwt,bcrypt
from .models import User
from django.db.models import Q
from django.conf import settings


def gen_token(user_id):  # 生成令牌趋箩;
    key = settings.SECRET_KEY
    return JsonResponse({
        'token':jwt.encode({'user_id':user_id},key,'HS256').decode()
    },status=201)

# register
def reg(request:HttpRequest):
    print(request.body)

    try:
        payload = simplejson.loads(request.body)  # 用戶數(shù)據(jù)Json化 提交;
        print(type(settings))

        email = payload['email']      # 提取內(nèi)容
        query = User.objects.filter(email=email)   # 看email是否已經(jīng)存在加派;
        if query.first():  # 查一下: email 如果存在叫确,則return error;
            print('============================')
            return HttpResponseBadRequest('用戶名已存在')

        # 用戶名不存在,繼續(xù)向下芍锦;
        name = payload['name']   #
        password = payload['password']

        user = User()
        user.email = email
        user.name = name
        user.password = bcrypt.hashpw(password.encode(),bcrypt.gensalt())   # 密碼采用bcrypt加密竹勉;

        try:
            user.save()    #保存到數(shù)據(jù)庫test,唯一鍵約束
            return gen_token(user.id)   # 保存數(shù)據(jù)后返回一個令牌數(shù)據(jù)回去;
        # 可以返回user_id status=201(注冊成功 重新登錄) 或者 token(登錄)

        except Exception as e:
            return JsonResponse({'reason':'asdaf'},status=400)
    except Exception as e:
        print(e)
        return HttpResponseBadRequest('參數(shù)錯誤')


def login(request:HttpRequest):
    try:
        payload = simplejson.loads(request.body)
        email = payload['email']
        password = payload['password']

        user = User.objects.filter(email=email).first()
        if user:
            if bcrypt.checkpw(password.encode(),user.password.encode()):
                return gen_token(user.id)
            else:
                return HttpResponseBadRequest('登錄失敗3')
        else:
            return HttpResponseBadRequest('登錄失敗1')


    except Exception as e:   # 記錄登錄日志娄琉;
        print(e)
        return HttpResponseBadRequest('登錄失敗2')

def show(request):          # 方法的使用方式各不相同次乓;
    users = User.objects.all()
    print(users.values())# objects
    return JsonResponse({})
#---------------------------------------------------
{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo4fQ.-c9iliH6cV9PmsnxL-73ptlIetVsWvA-dUG5MBcboOU"
}
from django.http import JsonResponse,HttpRequest,HttpResponseBadRequest
import simplejson,jwt,bcrypt
from .models import User
from django.db.models import Q
from django.conf import settings


def gen_token(user_id):  # 生成令牌;
    key = settings.SECRET_KEY
    return jwt.encode({'user_id':user_id},key,'HS256').decode()

# register
def reg(request:HttpRequest):
    print(request.body)

    try:
        payload = simplejson.loads(request.body)  # 用戶數(shù)據(jù)Json化 提交孽水;
        print(type(settings))

        email = payload['email']      # 提取內(nèi)容
        query = User.objects.filter(email=email)   # 看email是否已經(jīng)存在票腰;
        if query.first():  # 查一下: email 如果存在,則return error;
            print('============================')
            return HttpResponseBadRequest('用戶名已存在')

        # 用戶名不存在女气,繼續(xù)向下杏慰;
        name = payload['name']   #
        password = payload['password']

        user = User()
        user.email = email
        user.name = name
        user.password = bcrypt.hashpw(password.encode(),bcrypt.gensalt())   # 密碼采用bcrypt加密;

        try:
            user.save()    #保存到數(shù)據(jù)庫test,唯一鍵約束
            return JsonResponse({
                'user_id':user.id
            })   # 保存數(shù)據(jù)后返回一個令牌數(shù)據(jù)回去炼鞠;
        # 可以返回user_id status=201(注冊成功 重新登錄) 或者 token(登錄)

        except Exception as e:
            return JsonResponse({'reason':'asdaf'},status=400)
    except Exception as e:
        print(e)
        return HttpResponseBadRequest('參數(shù)錯誤')


def login(request:HttpRequest):
    try:
        payload = simplejson.loads(request.body)
        email = payload['email']
        password = payload['password']

        user = User.objects.filter(email=email).first()
        if user:
            if bcrypt.checkpw(password.encode(),user.password.encode()):
                token = gen_token(user.id)
                res = JsonResponse({
                    'user':{
                        'user_id': user.id,
                        'name': user.name,
                        'email': user.email
                    }, 'token': token
                })

                res.set_cookie('jwt',token)  # 演示 如何 set_cookie

                return res
            else:
                return HttpResponseBadRequest('登錄失敗3')
        else:
            return HttpResponseBadRequest('登錄失敗1')


    except Exception as e:   # 記錄登錄日志缘滥;
        print(e)
        return HttpResponseBadRequest('登錄失敗2')

def show(request):          # 方法的使用方式各不相同;
    users = User.objects.all()
    print(users.values())# objects
    return JsonResponse({})
# --------------------------------------------------------
{
    "user": {
        "user_id": 8,
        "name": "sunny",
        "email": "sunny@magedu.com"
    },
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo4fQ.-c9iliH6cV9PmsnxL-73ptlIetVsWvA-dUG5MBcboOU"
}
2. 認(rèn)證接口

如何獲取瀏覽器提交的token信息簇搅?
1完域、使用Header中的Authorization
通過這個header增加token信息。
通過header發(fā)送數(shù)據(jù)瘩将,方法可以是Post、Get

2.自定義header
JWT來發(fā)送token
我們選擇第二種方式

認(rèn)證

基本上所有的業(yè)務(wù)都需要認(rèn)證用戶的信息。
在這里比較時間戳姿现,如果過期肠仪,就直接拋未認(rèn)證401,客戶端收到后就該直接跳轉(zhuǎn)到登錄頁备典。
如果沒有提交userid咪辱, 就直接重新登錄饲嗽。如果用戶查到了, 填充user對象。
request時間戳比較->userid比較>向后執(zhí)行

def show(request):          # 方法的使用方式各不相同吮旅;
    token = request.META.get('HTTP_JWT', None)
    # print(list(filter(lambda x: x.lower().endswith('jwt'),meta)))  #查詢 http_jwt
    print(token)
    key = settings.SECRET_KEY
    try:
        jwt.decode(token,key,algorithms=['HS256'])  # 解失敗,被改過被廓;接成功党觅;沒改過;
        print(payload)
    except Exception as e:
        print(e)
        return HttpResponseBadRequest('用戶名密碼錯誤')

    return JsonResponse({'status':'ok'})
from django.http import JsonResponse,HttpRequest,HttpResponseBadRequest
import simplejson,jwt,bcrypt,datetime
from .models import User
from django.db.models import Q
from django.conf import settings


def gen_token(user_id):  # 生成令牌倚喂;
    key = settings.SECRET_KEY
    return jwt.encode({'user_id':user_id,
                       'timestamp':int(datetime.datetime.now().timestamp())
                       },key,'HS256').decode()

# register
def reg(request:HttpRequest):
    print(request.body)

    try:
        payload = simplejson.loads(request.body)  # 用戶數(shù)據(jù)Json化 提交每篷;
        print(type(settings))

        email = payload['email']      # 提取內(nèi)容
        query = User.objects.filter(email=email)   # 看email是否已經(jīng)存在;
        if query.first():  # 查一下: email 如果存在端圈,則return error;
            print('============================')
            return HttpResponseBadRequest('用戶名已存在')

        # 用戶名不存在焦读,繼續(xù)向下;
        name = payload['name']   #
        password = payload['password']

        user = User()
        user.email = email
        user.name = name
        user.password = bcrypt.hashpw(password.encode(),bcrypt.gensalt())   # 密碼采用bcrypt加密舱权;鹽一直在變矗晃,強(qiáng)加密;

        try:
            user.save()    #保存到數(shù)據(jù)庫test,唯一鍵約束
            return JsonResponse({
                'user_id':user.id
            })   # 保存數(shù)據(jù)后返回一個令牌數(shù)據(jù)回去宴倍;
        # 可以返回user_id status=201(注冊成功 重新登錄) 或者 token(登錄)

        except Exception as e:
            return JsonResponse({'reason':'asdaf'},status=400)
    except Exception as e:
        print(e)
        return HttpResponseBadRequest('參數(shù)錯誤')


def login(request:HttpRequest):
    try:
        payload = simplejson.loads(request.body)
        email = payload['email']
        password = payload['password']

        user = User.objects.filter(email=email).first()
        if user:  # 登錄成功张症,返回信息
            if bcrypt.checkpw(password.encode(),user.password.encode()):
                token = gen_token(user.id)
                res = JsonResponse({
                    'user':{
                        'user_id': user.id,
                        'name': user.name,
                        'email': user.email
                    }, 'token': token
                })

                res.set_cookie('jwt',token)  # 演示 如何 set_cookie

                return res
            else:
                return HttpResponseBadRequest('登錄失敗3')
        else:
            return HttpResponseBadRequest('登錄失敗1')

    except Exception as e:   # 記錄登錄日志;
        print(e)
        return HttpResponseBadRequest('登錄失敗2')
# 誰認(rèn)證就給誰加裝飾器啊楚;
def auth(view_func):
    def wrapper(request:HttpRequest):
        token = request.META.get('HTTP_JWT', None)  # 拿到http_jwt 字典的值
        # print(list(filter(lambda x: x.lower().endswith('jwt'),meta)))  #查詢 http_jwt
        print(token)
        key = settings.SECRET_KEY
        try:
            print('=============================')
            jwt.decode(token, key, algorithms=['HS256'])  # 解失敗吠冤,被改過;接成功恭理;沒改過拯辙;
            print(payload)
            user = User.objects.filter(pk=payload['user_id']).first()   # 查詢一次數(shù)據(jù)庫;
            # user = User.objects.filter(pk=payload['user_id']).filter(isactive=True).first()

            if user: # 拿到user,
                request.user = user  #request 動態(tài)添加屬性颜价;
                ret = view_func(request)

                return ret
            else:
                return HttpResponseBadRequest('1用戶名密碼錯誤')
        except Exception as e:
            print(e)
            return HttpResponseBadRequest('2用戶名密碼錯誤')

    return wrapper

@auth        # 認(rèn)證攔截
def show(request):          # 方法的使用方式各不相同涯保;
    print(request.user,'---------------------------')
    return JsonResponse({'status':'ok'})
#----------------------------------------------------------
{
    "user": {
        "user_id": 8,
        "name": "sunny",
        "email": "sunny@magedu.com"
    },
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo4LCJ0aW1lc3RhbXAiOjE1OTc1MDE3NDIuODYxNzA3fQ.jOOTyLE6GeXMmdCmYhGmw5fjj2BQoHWPmtx8ppvYUrU"
}
post 提取cookie - session
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市周伦,隨后出現(xiàn)的幾起案子夕春,更是在濱河造成了極大的恐慌,老刑警劉巖专挪,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件及志,死亡現(xiàn)場離奇詭異片排,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)速侈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門率寡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人倚搬,你說我怎么就攤上這事冶共。” “怎么了每界?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵捅僵,是天一觀的道長。 經(jīng)常有香客問我眨层,道長庙楚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任谐岁,我火速辦了婚禮醋奠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伊佃。我一直安慰自己窜司,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布航揉。 她就那樣靜靜地躺著塞祈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帅涂。 梳的紋絲不亂的頭發(fā)上议薪,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機(jī)與錄音媳友,去河邊找鬼斯议。 笑死,一個胖子當(dāng)著我的面吹牛醇锚,可吹牛的內(nèi)容都是我干的哼御。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼焊唬,長吁一口氣:“原來是場噩夢啊……” “哼恋昼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赶促,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤液肌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鸥滨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嗦哆,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谤祖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了吝秕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泊脐。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡空幻,死狀恐怖烁峭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秕铛,我是刑警寧澤约郁,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站但两,受9級特大地震影響鬓梅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谨湘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一绽快、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧紧阔,春花似錦坊罢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乖仇,卻和暖如春憾儒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乃沙。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工起趾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人警儒。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓训裆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親冷蚂。 傳聞我的和親對象是個殘疾皇子缭保,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348