From 88b75e1e9cc1a9345ea478d65fe9d7fa7a9cbc3e Mon Sep 17 00:00:00 2001 From: TBS093A Date: Sat, 20 Jun 2020 17:16:55 +0200 Subject: [PATCH] add full authorization --- portfolio/__pycache__/settings.cpython-36.pyc | Bin 2819 -> 2794 bytes portfolio/__pycache__/urls.cpython-36.pyc | Bin 1997 -> 1889 bytes .../account/__pycache__/models.cpython-36.pyc | Bin 2560 -> 2264 bytes .../__pycache__/serializers.cpython-36.pyc | Bin 2192 -> 3417 bytes .../account/__pycache__/views.cpython-36.pyc | Bin 1537 -> 2449 bytes portfolio/account/models.py | 42 +++++++++--------- portfolio/account/serializers.py | 35 ++++++++++++++- portfolio/account/views.py | 27 ++++++++++- portfolio/settings.py | 6 ++- portfolio/urls.py | 11 ++--- 10 files changed, 88 insertions(+), 33 deletions(-) diff --git a/portfolio/__pycache__/settings.cpython-36.pyc b/portfolio/__pycache__/settings.cpython-36.pyc index 9c26ff93adf57f158a6b993d9b1335e6d7fbc3e2..65be4c8e4d2b980189c0e8fe8fed8c02db07f847 100644 GIT binary patch delta 87 zcmZn`dnL+g%*)HAAp9-spa`a*?I-3MY);9#hLke#d@B_ rjw!jBd7;IrMU&lGO_{0;CwsEWv4rGjr*6(=4QFNMU}2ejoXZ9PBYqsR delta 124 zcmaDQ+APLt%*)FqY4JKvek12;76<#H)Z&u(w4%h^)bjkIY`uciqTI~l;>`TKVm+6v z#Ju!;-~5!+oB)Kdf01KeeqK;&Vv2uWPUU0+Rs~_F#Ny0k$I_CF)Vz|+}YHgQMs^I z+5!tuI{tu~&p`ZuJ46Kq-@u(nASf7Vq;t+aI`_`pFV0tc{J^q|r{w3$A1Wc=$X`cC z{1|U~|NZz$v9vsk5}=?i?4{#%wpd&2EM3n?|6WWScPH{pb!H;I_dO>R~NO|Ac#U9@FM4W`p1XK}VET5s>RFC~k!OZ3-jkovN_r>?{7 n%Fn}(M4Zc(=bNFr(jOvJs7bq<59*o2?1o8QMPnwlsm*=?>k^r! delta 671 zcma)3yN=U96!qANorhy5>twUZW;dGzX|+NGBq|UE?Mf6#NEB0GjeIALjUUn2A%Z4F z3L2~h`75X?_z1)gq(f9l`~V%-hLzZkk!I$cbMKjZXXcyn)tudLwHnXg{(SLHlcev` zKckNLG0x=ahuP(pNI*afTA@LW(4=O`Ye75g&`yc#!9i$I3vmOQK{xEt9+9}t8~!2a z(1HT>!2mNOh>oBQos7UiRt1Zj{$N3%n<;e24gYv2(Gef{C(z?P{}c|PpKTR9tdNdS z8t-Ie6&P^YKl3L$8S#*-7@zD&$&R@SBRGN6Oy0?^LZ{sFXYYx4^8YT(9P^=n3(oN3 z6Qew+LZ>i&CSA-vQF0{@1-Dl$UG6n6a)LGR3$j;}l%<}N|56^@Zo53SlMQoSF6>tx z-(b9!@HF)zH~B&EX;G*afh51Ie0fx7EAI|lr^~x4_K#xSFuPJap1+4&08!uhjYwx2Z&QTNR g`Db<2e2B0@bkZeyeovcrh@t4jAYG*<7kiuh22=I3;{X5v diff --git a/portfolio/account/__pycache__/models.cpython-36.pyc b/portfolio/account/__pycache__/models.cpython-36.pyc index 89e037e13c9d26f9c98310586f5b5af4ce44215e..51fa655490283b16fdafaee2395cc056bac066c1 100644 GIT binary patch literal 2264 zcmZ8jOK&4Z5bo}I+Mbwfw6Myuf`G(hkg$=E-~d8d60sn$)@lI>&4JNmx|7(M@tB@5 zOQP(_k@mzt*gwFp;oetHd*KIgfvNImx0BrIR>Tb_%!j63@zR;g>-YSlKJWvXgW;d&HzKgDWNj#V6f` zlk}hoWe1v$@>Fl(CJ{7U*@LEszLRXp=m!>Wy~4>X=Eg58sfrp>^lj73o~n9QO>2d| z`%|qnzTt+h2h}($#urN0Iqk4&E`)theF&yl!X-9zl}@u#nQoc=o)&6) z(wrv2K{cN?`aBWeJ$dySX5TQAL$MF4x4~9sN}f1U;7I4<&gPMW$EwMG9L25)Q+rUF znr@oHVe>*kj?(nkc~+1K=!MzR+CQ15-7Wj~cz9ZsYFMdqcvzjyOEqoIhfj1hQF&7j zXO(V_t72STOJ8UC*)W^UigBJb<7#?6vLR)8PAG?M>;|)Q=pZp3(IS6(A%r8~4X0PBG25G>?<`U$JO;bTe# zYV}jFYadH-#S%xk(s{|HE4?chDd8{sl*I0WC&98$DeNZU3wF$H@`g$01#?-_MU)~F zJZ$mjgoYY@i4H(Ew3lqcCj62wY)xSiA0cZHMmf$K1k0b#WY#F?+*%dK#wGm*Xu@m4 zV_lVp7`RK@+Ozn@_VVn(YLIG3t7fjJIb|0$`jU^VIeQSu91w~ET!0*q3-Tm?8NfU- ziUT-bnsAO>w@Dq&vbug&X=yxFX5&J?fsHhoqF)D#ef<{6Zxefm*sXD{?~`_&irQlG zn~D(K!%$5L!Gz0QE07OL$tV5-PQo`>FrW`c8!+~;`)w?tCWB2-9of1uy<97VFC}N)nu~yD zxE$Wae2O^DAiySA*34~(gj$`9>!w{%Q`IoxbNY2fmq)zI!;PS?Ca*Kkq4^-|n9m?c zfIai|1Av3P;Lj=C{8CURLK1CGLUODNkOtNTVx;%5I`)h+t7ayuRgt;D&-lgNRfcUMjC;55DGT{ctgw*bj|R74 zUaID_lKMl^6H052*;<~PtD;z)O)iPK{+K3NJ1BuDx)xq2LZ{yod^_s5sg+}7-PVr; z`S1DyqcSz#qq(Y^QS96{_&NqwvS)sR^@^Xg5+VU|b~-!p|9`yfEdT%j literal 2560 zcmZuz&2HO95Z>j#BuaLiq=B2X4O%p)E*AQOq6OL_iGwBu5;aKD3lAk|?%I}2it3U| zYC%59KrYQ2^aa{S+G|fi-=LTFo24YnLMiNMb~&8g`R1D;KX132KmPgm&o_O>{$gvF z3;ixe`5S~_f@dt}5$B{^nU&j-ZFDN50YBEXW&C!{}bt%v({*=zbRF z?WoP!LnZ>zIA@|E`LHv$qb;m7MGGq}>B_CS6K!K96m6`uF}I^DqVt?}x8CAJtjo2R z7eZzwwD3_?ji1SKT#QPIx${#g6|ER67dL7G&w9<158FNza6!eR@ygCrYFr7BZ$ zy}TSKcQMMx5Rye)u*j13&=Fi%!hT~#u9-QDnP+CM@XS45_#!xGQGg&CqKP1yb1Q0y z7D5Phc<-RBRFYP7(#Y8#RHtwM#Wr0_hcBf%C`uWRl3eO$p8OhTa&%N3NB({>8CB{u zvVM5_b_>?21wj}6)7Zx-w;^V1$cB8z=O$y=lK0^{h+{EGt2ox)WGo01OFN~^4z)w; ze=xO!Xa70u9T&Om6*BKVC{89h5IpTYRmD)IRoNRCsyZyPL2;qoPtucKG9G6H^q?4B z+*#9-G^OMB>a6XJPjzspiu?gKrW2PY7Cybcj?CWD;!>OLStT#}U5BD4ND+NAj&X`fMtT^>zf6*BaVJO?c`-<=iL2O3JLHQrbJ&2ZUFiL8 zQ(ecudWXaf5)_JV>>nrU`+>}ac2eY5`zC&Ms;$9TT_Zbsd~FW`Uy*y&fM{WqO^ASZ z=w}7CS-%7Yag?qNj!JO!cf-&&(a+o;#5bhWf<{qHFH>0 zbJV|AXACvsDOpX_C?(|Sq5!Ew7`{D%Qh{wlYlc3t3+@TaNPCyf?K6(KgE^0FXzngH zgYH20%&I%%LvPMFERa3FuY(C{!jRvUc{0d!Fiy(yRiT7>4_m35ByK@;ef2*6v|k(; zYU)<1Bv>7jgAH5oJb6icH{OYK+FvkoEdwUYfs#jqvXUk}B_)Mf9;aW^YVwdbdBCUJ z3vl+9#;Hw)xI7F>i^1kTlnRl}EWzJcXZFk%?4+T-tbo?go*_kV_?c5Vn7K0tjf0=L zGk54c2WG+@01?4}iihe|x8X~D2+`$6M_wF?RJ(|_P}49gjs~OKhk#59U_%Kq0I83l zY5Pc43T>WguZBr=$d{+6iY}Z-0XocM@}#{iq#H!*U}UUy(nh7b&})HL<1X?qEc zu~~73xI@F>LI9b_c;C22Nah%(1XgvRJ-8?)RS(w7{?J+Tj$5l1NbnOajr-5YJ!p2~ zsav2I^f^BRJ<$>^YKhRSx;a9#iG1cTR=>vA(e}6)>#&qnyyBjz*pK13Yu9I`=#Bjb zIEq>`oxoHt129eVo34&tH{aFK>DV+V1OsQq=8NvV?A&fS86(S|!U9YnsC1~3SF6*3 z3ynBVGZac3*XJQFn+Luox8$Gk>9r+#>!EeSjRuCuD>U*nm(_70v{%=c`h+}QA+bk- zvSMO2yXf{}|5Rq#@(h$or1lH4H0Pmur50(z3@nRphn+@X2X!TRbr3=T~_CTMUB%nl{b*-5uQ!!(?<+?1_WAVYe3ZV|+{~%7uP+ zv62>e?G6t1=yPJPet#)qu)g{~2Bz-x4TS^7hYBwobgmP$iTdkAQG3uIY}_Tsrp}h$ zO`UcwTd9B^b)V2zk9iZ+#ZBR?G0+50aqHll`X%=rA!+(ph%&{`GSc1&ckcWLh_pba diff --git a/portfolio/account/__pycache__/serializers.cpython-36.pyc b/portfolio/account/__pycache__/serializers.cpython-36.pyc index 1213bb23017b2b2c6979f497a400866685cb964e..f28f03dfedc4b0f32200b937f83776bfbbebd979 100644 GIT binary patch literal 3417 zcmbVOOLH4V5Z>9hq?PSBPRI)qC?F*YY#>#fAmuzDkOCJ)r~>v7v1rEf%KH$rBS0$U zNFfz}`nuhlc-#W%exMsjZTr)hd<2G;LicP&SzuN<$9xbl(HEAnF z!n7eXc4PPq<8uyB#&LVF@l(hS0(c6+HB>%cffj(0k~4!d1i)a~kKx0{!Ilo20w zyFZSSY&IipD5O11icI^vsmOTsnX~C)GK-t7V}Y_c9BY?ucphh0lnNnpnS2GzPG?2F zL>gTpa+!z+qNC3WCHg{sLTbx%Bx>B-OXlNs8aF>C`^*;5#&Uzm1tJ%T(DwChXWYvq zYk|;Pt$>6q!f!?++srMwcM+K%U~%oo+t{ze zBD6~0S)T0a2L;p*oVPpBYoLPiexm-A=a^{{C11mL#uREe_cRS1G8wL>R#BuSSHwJ0xNVWu`z9i_m;BP{hrAVTguX9P`8-2(4Vq#_P&8V~0B!yWd#F6=u=T$i3-Y{+(6W-&#|5;7^@FaA0xw zx&6qZButSl+=9{pWeoY;SR1)UJhXHPVv#$ZqT(grh7@2cWho~S3Rha(*aff%-U%fI z;4JBa@&|*9+UW}=3G|Kow6ib9+E?ZMw5K{=eOw$WIsTk>GY80b=!*sRN|TqKIgLW0 zBGoLLfM|u;Y@PXRgRR+V1%@H9(7T8Q{T@u-v(9J+T#x zJaA!j)X*mmjOHD{s7D5av2>e!Tgr4|!2JcgAx$s9-=(!aN{#?DxH^#HN9rF?fJ&Js3T7drKT`5EiRXid0V_6DpGvdOhG zt$-$DDGw-Fx9NMznK}<0atMCa)gz2f3k7n1k*Xq;C;FNpW;2b_kV!$PqA#-dpn)hslK~T8&Y#J1NCJE&UV&qd~uf! zp%OoDJpk>Jfgc5cS%wv$of15o4Yu)e14w5uDi!7BOgrWw=NSE)iVT+gANe8N>E_uG+%Q#DqndZhbVRDOGu&h6MuWK&t6bNK3#ev@N z9~N3qzvmQP-wvxHyz9~Uv{J3^L}%0I2=HUDzo?dQYCE#ag@Zb6y#lq2K^N)w}@iei)DOkzb_9G Ub(`Uelq{^^k=V>uEvS_L0X~G4a{vGU diff --git a/portfolio/account/__pycache__/views.cpython-36.pyc b/portfolio/account/__pycache__/views.cpython-36.pyc index 4383903cdc8125345a9680dd157999c766746b0d..df9191c537a23cc41689e3dd9510a1ab58ca7f0e 100644 GIT binary patch literal 2449 zcmZ`)OOx9~5Y~*IetTaD0VO!wE1x!vhB|Jwfdw?BQ$`o}u= zbAZ1GkNh17vlz*(f<&aC5iRVgThWGMz z(TO_1`z*-2MK9_V{itug8~Mgl>!HP(to7PrEl#GJ$9A*@k~Zsrq{ChK-iGfk>%n)g zw%B3)Csw%e2E4RFTL&*PejvG$+AFe`*-YxzoQoopGAm~?B)a$LnM$(R{e{|lTJG~1 zh=O0ZoP(AFza>MT(xC{?1T+3=(cdgjo^g_SBiW$5!NVKMHtb+MJN6#oLVV zPDU6#AuM1Hb6=BV5_K=gJ?6i*K-yzApwQ6W+JRpIg(qCS`5TTw_eC9{9H(~eiwkdb z=LdM?=RlOTqQ`_-ima?DT~S6(=#j1Lm3>T(9ObOgNdm{vF>Fca`=O`ZxyWWpG+?<7 zo-epK1nl*8?Zrc`o^X*RdA8(2cxdFXL?xlC9m(@u?F$Zzq!Jsb^OG9AraW8qhb7(x z-G6+vR~CF!@?!L$++P%YrVdAsMTtp}qj@RRZkcE0n)^OU_eaTmo@Z&IAopv{Ij%l% zWQt}uKh%NXN@V;6--1JB0K}pJ>5_mfuU~|Acxstaw1VF$ppSr;?*IWnttnxcK?(p; z01%)A0PXQpK+q|Y*yhoJP|o`Y_!c)%j*wL3J!6q) zQlU&@LM_@Q%dJb^qD4r?VP6MvJWC25$GREEMadR9^6fZ&zDV*)BU-qtUzNDjc9Q4D z!Dyr2b)8k+U*{@L^F&I4KIq<05?c(?g!pr&H`i@g*>Ndg=2%tu?;|%rvJTB~7@z0@ z>A)k~Kmyt%4hd+Rv^}G_y1{+~)3-GkrX(ZWXZ8s-jfE}Lte(1I|;9a;M(PU3tgQuHc+MHgy6=W9eu=EoX|q zR9Ip?kz|s`{AJ4L*aSLQK)Nu=I+#PQ4obm7Uwj7Zs>MMj;}_7cOn1!-Qx{{)R^7XE z4ux|y;N~SvN7(4BXvIz3@&hEMV829eh-97Ls&wb2RG)%EHi1~~HffV4{FnW6M-9@msJ^nwF=_&GSB1>T%c>AA*Va2+7Atu$jasNHET-)4xK_z;1frHhzAMWPRwm z{6kO-;8~YHrNkrshCt1Q^2dAV9-89ntIMC65w6?jhN|z0aoD)*HMZI%ucMw>vrc>! z!BsAQ1FJC}Gmrwvr$EU#yr#Qw6{&bvKn+6m?F)obVAjmsh;Cj~58)c#Q+Q7g&5RZ} zWcBq+MyI!%No~|+VmCfaQt;vY^fDJX;dQ^(N$6sgE|je9 zGY^I%hxI0Z2#0R1XPu1NKcl(^&I G@B9y*?NCzy delta 846 zcmZuvyKWOf6rI`k({B?eydN%1;R2|5DbN@RL1T$xBtRR_V6B<;hM6@{D2Px}&``h@ z`~VF-Jp~OCf3PhT5)FUA+)3oP$Vz+m+%tFXoO@?Kw%vcoVk>I-!@6;m1u3S+2TVO`QTqVzV-hl- z;-#*dI6z8`%Afdc*HIoS@702dU1dQ;DimhPjniivu;M0%UaCMY-F!u&SAH=H+$`74 z*#o_$rS}1}6%1_A0p3+mS&5j+%6Yj1U$F*yZwc!~^$|BMH!n{Un7 zq>z=Fa4z%#fzr!OYwgaV&kZPZ4&b<;W>8hc3c#C$U7itO%ZPB~h`9XjJ|yQM dict: + return { + 'id': self.id, + 'username': self.username, + 'password': None, + 'email': self.email, + 'ip': self.ip, + 'city': self.city, + 'country': self.country + } + @staticmethod - def register(userDict) -> object: + def register(userDict) -> dict: account = Account.objects.create_user( userDict['username'], userDict['email'], @@ -33,26 +42,15 @@ class Account(User, AbstractUser): account.city = userDict['city'], account.country = userDict['country'] account.save() - return account + return account.toDict() - def login(self, username, password) -> dict: - tryLogin = authenticate(username = username, password = password) - if tryLogin is not None: - user = Account.objects.get(username = username) - token = Token.objects.create(user = user) - return token.__dict__ - else: - return { 'error': 'login failed'} - - def logout(self): - pass - - def update(self, userDict): + def update(self, userDict) -> dict: if 'password' in userDict: password = userDict.pop('password') self.set_password(password) self.fromDict(userDict) - self.save() + self.save() + return self.toDict() def set_password(self, raw_password): return super().set_password(raw_password) diff --git a/portfolio/account/serializers.py b/portfolio/account/serializers.py index 58a09a6..45d39c7 100644 --- a/portfolio/account/serializers.py +++ b/portfolio/account/serializers.py @@ -1,6 +1,9 @@ from .models import Account, Guest -from rest_framework import serializers +from rest_framework import serializers +from rest_framework.authtoken.models import Token + +from django.contrib.auth import authenticate, logout from django.core.paginator import Paginator from django.http import JsonResponse @@ -25,12 +28,40 @@ class AccountSerializer(AccountGetSerializer): return Account.register(validated_data) def update(self, instance, validated_data): - return instance.update(instance, **validated_data) + return instance.update(validated_data) class Meta: model = Account fields = ['id', 'username', 'password', 'email', 'ip', 'city', 'country'] +class AccountAuthSerializer(serializers.ModelSerializer): + username = serializers.CharField(max_length = 100) + password = serializers.CharField(max_length = 100) + + @staticmethod + def login(username, password) -> dict: + tryLogin = authenticate(username = username, password = password) + if tryLogin is not None: + user = Account.objects.get(username = username) + try: + token = Token.objects.get(user = user) + except: + token = Token.objects.create(user = user) + return { 'token': token.key, 'user': user.toDict() } + else: + return { 'error': 'login failed'} + + @staticmethod + def logout(request, format=None): + tokenStr = request.headers['Authorization'].split(' ')[1] + token = Token.objects.get(key = tokenStr) + token.delete() + return { 'info': 'logout' } + + class Meta: + model = Account + fields = ['username', 'password'] + class GuestSerializer(serializers.HyperlinkedModelSerializer): id = serializers.IntegerField(read_only = True) diff --git a/portfolio/account/views.py b/portfolio/account/views.py index 03c55f6..cf2419f 100644 --- a/portfolio/account/views.py +++ b/portfolio/account/views.py @@ -1,4 +1,5 @@ -from rest_framework import viewsets +from rest_framework import viewsets, mixins, permissions +from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.response import Response from drf_yasg.utils import swagger_auto_schema @@ -6,13 +7,14 @@ from django.core.paginator import Paginator from django.shortcuts import get_object_or_404 from .models import Account, Guest -from .serializers import AccountSerializer, GuestSerializer, AccountGetSerializer +from .serializers import * class AccountViewSet(viewsets.ModelViewSet): queryset = Account.objects.all() serializer_class = AccountSerializer + permission_classes = [permissions.IsAuthenticated] @swagger_auto_schema(responses={ 200: AccountGetSerializer }) def retrieve(self, request, pk=None): @@ -27,6 +29,27 @@ class AccountViewSet(viewsets.ModelViewSet): return Response(serializer.data) +class AccountAuth(ObtainAuthToken): + + queryset = Account.objects.all() + serializer_class = AccountAuthSerializer + + @swagger_auto_schema( + responses={ 200: '{ Token: Authorize }' }, + request_body=AccountAuthSerializer + ) + def post(self, request, *args, **kwargs): + serializer = self.serializer_class(data=request.data, context={'request': request}) + serializer.is_valid(raise_exception=True) + username = serializer.validated_data['username'] + password = serializer.validated_data['password'] + return Response(AccountAuthSerializer.login(username, password)) + + @swagger_auto_schema(responses={ 200: '{ info: logout }' }) + def delete(self, request, *args, **kwargs): + return Response(self.serializer_class.logout(request)) + + class GuestViewSet(viewsets.ModelViewSet): queryset = Guest.objects.all() serializer_class = GuestSerializer diff --git a/portfolio/settings.py b/portfolio/settings.py index baee004..cd5ea0d 100644 --- a/portfolio/settings.py +++ b/portfolio/settings.py @@ -57,11 +57,13 @@ REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' + # 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly', + 'rest_framework.permissions.IsAdminUser' ], 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.BasicAuthentication', + # 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', + 'rest_framework.authentication.TokenAuthentication', ] } diff --git a/portfolio/urls.py b/portfolio/urls.py index f24424a..5440999 100644 --- a/portfolio/urls.py +++ b/portfolio/urls.py @@ -14,13 +14,12 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path, re_path, include -from django.conf.urls.static import static +from django.urls import path, include, re_path from drf_yasg import openapi from drf_yasg.views import get_schema_view from rest_framework import routers, permissions -from rest_framework_swagger.views import get_swagger_view +from rest_framework.authtoken import views as authViews from portfolio import settings from .account import views @@ -40,18 +39,20 @@ schema_view = get_schema_view( router = routers.DefaultRouter() router.register(r'users', views.AccountViewSet, basename='user') +# router.register(r'users/auth', views.AccountAuth, basename='user auth') router.register(r'guests', views.GuestViewSet) urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls)), - path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) + # path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) ] if settings.DEBUG: urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls)), - path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), + re_path(r'users/auth', views.AccountAuth.as_view()), + # path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0)) ] \ No newline at end of file