MY MEMO

[IONIC+Django] 로그인, 회원가입을 위한 Token Authentication 본문

STUDYING/APPLICATION

[IONIC+Django] 로그인, 회원가입을 위한 Token Authentication

l_j_yeon 2018. 1. 28. 22:18

+) https://www.youtube.com/watch?v=0jSzFUZ__k8 이 유튜브 강의에 매우 자세하고 완벽하게 나와있다

따라하기만 하면 가능하기 때문에 그대로 하면 된다

(Token Authentication 관련 동영상은 29,31,32이다!)


+) User 테이블을 생성하지 않아도 default 테이블이 존재한다 (AbstratUser)

하지만 새로 정의해줘도 괜찮다


models.py

: AbstractUser가 Django에 있는 기본 테이블이다 

그 테이블을 상속시켜주고 username을 Email Field로 변경했다 (변경을 해주지 않아도 괜찮다)

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
username = models.EmailField(unique=True, null=False, max_length=254)

admin.py

: localhost:8000/admin에 보이기 위해서 admin.py를 변경한다

class UserAdmin(admin.ModelAdmin):
list_display = ('username', 'password','email','is_superuser')

admin.site.register(User, UserAdmin)

Setting.py 

REST_FRAMEWORK = {

'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),

'DEFAULT_RENDERER_CLASSES': (
# 자동으로 json으로 바꿔줌
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
),

# 기본적인 permission 정의 가능
'DEFAULT_PERMISSION_CLASSES':(
'rest_framework.permissions.IsAuthenticated',
)
}
AUTH_USER_MODEL = 'api.User'

JWT : Json Web Token 

=> pip install jwt


IsAuthenticated : 기본적인 Permission 정의 

(즉 permission_classes를 정의하지 않으면 DEFAULT_PERMISSION_CLASSES안에 있는 권한이 기본 권한으로 정의된다)


AUTH_USER_MODEL = Application이름.User테이블의 이름


serializers.py

from rest_framework import serializers
from ..models import BlogPost, User
from django.core.validators import ValidationError

from django.db.models import Q

class UserCreateSerializer(serializers.HyperlinkedModelSerializer):

def create(self, validated_data):
username = validated_data['username']
email = validated_data['email']
password = validated_data['password']

user_obj = User(
username = username,
email = email
)

user_obj.set_password(password)
user_obj.save()

return validated_data

class Meta:
model = User
fields = [
'username',
'password',
'email',
'is_superuser',
]

class UserLoginSerializer(serializers.ModelSerializer):

token = serializers.CharField(allow_blank=True,read_only=True)
username = serializers.EmailField(required=False, allow_blank=True)
email = serializers.EmailField(label='Email Address',required=False, allow_blank=True)

class Meta:
model = User
fields = [
'username',
'email',
'password',
'token',
]
extra_kwargs = {'password':{"write_only":True}}

def validate(self, data):

email = data.get("email", None)
username = data.get("username", None)
password = data.get("password",None)

if not email and not username :
raise ValidationError("A username and email is required to login")

user = User.objects.filter(
Q(email=email)|
Q(username=username)
).distinct()

if user.exists() and user.count() == 1:
user_obj = user.first()
else:
raise ValidationError("A username/email is not valid")

if user_obj:
if not user_obj.check_password(password):
raise ValidationError("Incorrect credentials please try again")

return data

views.py

: permission_classes = [AllowAny] : 모두 허가한다

UserRegisterAPIView에서 ListCreateAPIView를 이용하면 /register를 했을 때 모든 계정의 비밀번호와 아이디를 볼 수 있다

하지만 이는 보안이 약해질 우려가 있기 때문에 generics.CreateAPIView로 변경해주는 것이 보안에 편하다

아래는 좀 더 편하게 개발하기 위해 ListCreateAPIView를 이용하여 구현하였다

class UserRegisterAPIView(generics.ListCreateAPIView):

serializer_class = UserCreateSerializer
permission_classes = [AllowAny]
queryset = User.objects.all()

class UserLoginAPIView(APIView):

# post를 하기 때문에 localhost:8000/api/test/login 으로 데이터를 확인할 수 없음
# localhost:8000/api/test/login으로 확인하기 위해서는!
serializer_class = UserLoginSerializer
permission_classes = [AllowAny]

def post(self, request, *args, **kwargs):
data = request.data
serializer = UserLoginSerializer(data=data)

if serializer.is_valid(raise_exception=True):
new_data = serializer.data
return Response(new_data, status=HTTP_200_OK)
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

urls.py

from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
url(r'^api-token-auth/', obtain_jwt_token), # Token을 가져오는 url
url(r'^register/', UserRegisterAPIView.as_view(),name='register'),
url(r'^login/', UserLoginAPIView.as_view(),name='login')
]

Login Api

: username 이나 email을 입력했을 경우 로그인이 가능


register api

: 비밀번호는 set_password 즉 hash를 이용해서 변경


Postman으로 Token을 확인했을 때

: body에서 username이나 password를 입력해서 token을 얻을 수 있음


Comments