Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/#18 #32

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 27 additions & 17 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
asgiref==3.3.1
certifi==2020.12.5
chardet==4.0.0
Django==3.1.3
django-debug-toolbar==3.1.1
django-rest-framework==0.1.0
djangorestframework==3.12.2
idna==2.10
mailjet-rest==1.3.4
mysqlclient==2.0.1
python-dotenv==0.15.0
pytz==2020.4
requests==2.25.1
sqlparse==0.4.1
urllib3==1.26.2
django-redis==4.12.1
redis==3.5.3
asgiref==3.3.1
certifi==2020.12.5
cffi==1.14.4
chardet==4.0.0
cryptography==3.3.1
defusedxml==0.6.0
Django==3.1.3
django-allauth==0.44.0
django-debug-toolbar==3.1.1
django-rest-framework==0.1.0
djangorestframework==3.12.2
idna==2.10
mailjet-rest==1.3.4
mysqlclient==2.0.1
oauthlib==3.1.0
python-dotenv==0.15.0
python3-openid==3.2.0
pycparser==2.20
PyJWT==2.0.0
pytz==2020.4
requests==2.25.1
requests-oauthlib==1.3.0
six==1.15.0
sqlparse==0.4.1
urllib3==1.26.2
django-redis==4.12.1
redis==3.5.3
Binary file added wadium/requirements.txt
Binary file not shown.
2 changes: 1 addition & 1 deletion wadium/story/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.db import models
from django.contrib.auth.models import User

from django.utils import timezone

class Story(models.Model):
writer = models.ForeignKey(User, related_name='stories', on_delete=models.CASCADE)
Expand Down
6 changes: 4 additions & 2 deletions wadium/story/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from user.serializers import UserSerializer



class StorySerializer(serializers.ModelSerializer):
writer = UserSerializer(read_only=True)
title = serializers.CharField(max_length=100, allow_blank=True)
Expand Down Expand Up @@ -48,7 +49,7 @@ def update(self, instance, validated_data):

story = super(StorySerializer, self).update(instance, validated_data)
return story


class SimpleStorySerializer(serializers.ModelSerializer):
writer = UserSerializer(read_only=True)
Expand Down Expand Up @@ -86,4 +87,5 @@ def create(self, validated_data):
validated_data['writer'] = self.context['user']
validated_data['story'] = self.context['story']
story = super(CommentSerializer, self).create(validated_data)
return story
return story

4 changes: 3 additions & 1 deletion wadium/story/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def get_serializer_class(self):
def get_permissions(self):
if self.action in ('retrieve', 'list', 'comment_list', 'main', 'trending'):
return (AllowAny(),)

return self.permission_classes

def create(self, request):
Expand Down Expand Up @@ -192,4 +193,5 @@ def comment_list(self, request, pk=None):
assert page is not None
serializer = CommentSerializer(page, many=True)

return self.get_paginated_response(serializer.data)
return self.get_paginated_response(serializer.data)

Empty file.
9 changes: 9 additions & 0 deletions wadium/user/providers/facebook/provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from allauth.socialaccount.providers.facebook.provider import FacebookProvider


class FacebookProviderNoRedirect(FacebookProvider):
id = 'facebook_no_redirect'
name = 'Custom Facebook'


provider_classes = [FacebookProviderNoRedirect]
9 changes: 9 additions & 0 deletions wadium/user/providers/facebook/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.urls import path
from .views import oauth2_callback, oauth2_login
from .provider import FacebookProviderNoRedirect
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns

urlpatterns = [
path("facebook/login/", oauth2_login, name='facebook_no_redirect_login'),
path("facebook/login/callback/", oauth2_callback, name='facebook_no_redirect_callback')
]
98 changes: 98 additions & 0 deletions wadium/user/providers/facebook/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from allauth.socialaccount.providers.facebook.views import (
OAuth2CallbackView,
OAuth2LoginView,
FacebookOAuth2Adapter,
)
from django.http import HttpResponseRedirect
from django.conf import settings
from .provider import FacebookProviderNoRedirect
from user.serializers import UserSerializer
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status


class SocialLoginView(APIView):
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?

try:
self.initial(request, *args, **kwargs)
except Exception as exc:
pass

def render(self, response):
query_string = self.request.META.get('QUERY_STRING')
if query_string:
queries = query_string.split('&')
for i in range(len(queries)):
if 'state' in queries[i]:
queries[i] = 'state=' + 'x' * 12
elif 'code' in queries[i]:
queries[i] = 'code=' + 'x' * 75
self.request.META['QUERY_STRING'] = '&'.join(queries)
self.response = self.finalize_response(self.request, response, *self.args, **self.kwargs)
return self.response


class TokenOAuth2CallbackView(OAuth2CallbackView):
def dispatch(self, request, *args, **kwargs):
api_view = SocialLoginView()
api_view.dispatch(request, *args, **kwargs)
res = super(TokenOAuth2CallbackView, self).dispatch(request, *args, **kwargs)
if isinstance(res, HttpResponseRedirect) and res.url == settings.LOGIN_REDIRECT_URL:
assert hasattr(request, 'user')
# login success
data = UserSerializer(instance=request.user).data
token, created = Token.objects.get_or_create(user=request.user)
data['token'] = token.key
res = Response(data=data)
else:
res = Response({
'error': 'An error occurred in social login.',
}, status=status.HTTP_400_BAD_REQUEST)
return api_view.render(res)


class TokenOAuth2LoginView(OAuth2LoginView):
def dispatch(self, request, *args, **kwargs):
api_view = SocialLoginView()
api_view.dispatch(request, *args, **kwargs)
res = super(TokenOAuth2LoginView, self).dispatch(request, *args, **kwargs)
if isinstance(res, HttpResponseRedirect) and res.url:
url = res.url
data = {
'url': url,
}
try:
queries = url.split('?')
queries = queries[1].split('&')
for query in queries:
if query[:6] == 'state=':
data['state'] = query[6:]
except:
pass
if 'state' not in data:
res = Response({
'error': 'An error occurred in social login.'
}, status=status.HTTP_400_BAD_REQUEST)
else:
res = Response(data)
else:
res = Response({
'error': 'An error occurred in social login.',
}, status=status.HTTP_400_BAD_REQUEST)
return api_view.render(res)


class FacebookOAuth2NoRedirectAdapter(FacebookOAuth2Adapter):
provider_id = FacebookProviderNoRedirect.id


oauth2_callback = TokenOAuth2CallbackView.adapter_view(FacebookOAuth2NoRedirectAdapter)
oauth2_login = TokenOAuth2LoginView.adapter_view(FacebookOAuth2NoRedirectAdapter)
Empty file.
9 changes: 9 additions & 0 deletions wadium/user/providers/google/provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from allauth.socialaccount.providers.google.provider import GoogleProvider


class GoogleProviderNoRedirect(GoogleProvider):
id = 'google_no_redirect'
name = 'Custom Google'


provider_classes = [GoogleProviderNoRedirect]
7 changes: 7 additions & 0 deletions wadium/user/providers/google/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.urls import path
from .views import oauth2_callback, oauth2_login

urlpatterns = [
path("google/login/", oauth2_login, name='google_no_redirect_login'),
path("google/login/callback/", oauth2_callback, name='google_no_redirect_callback')
]
98 changes: 98 additions & 0 deletions wadium/user/providers/google/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from allauth.socialaccount.providers.google.views import (
OAuth2CallbackView,
OAuth2LoginView,
GoogleOAuth2Adapter,
)
from django.http import HttpResponseRedirect
from django.conf import settings
from .provider import GoogleProviderNoRedirect
from user.serializers import UserSerializer
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status


class SocialLoginView(APIView):
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?

try:
self.initial(request, *args, **kwargs)
except Exception as exc:
pass

def render(self, response):
query_string = self.request.META.get('QUERY_STRING')
if query_string:
queries = query_string.split('&')
for i in range(len(queries)):
if 'state' in queries[i]:
queries[i] = 'state=' + 'x' * 12
elif 'code' in queries[i]:
queries[i] = 'code=' + 'x' * 75
self.request.META['QUERY_STRING'] = '&'.join(queries)
self.response = self.finalize_response(self.request, response, *self.args, **self.kwargs)
return self.response


class TokenOAuth2CallbackView(OAuth2CallbackView):
def dispatch(self, request, *args, **kwargs):
api_view = SocialLoginView()
api_view.dispatch(request, *args, **kwargs)
res = super(TokenOAuth2CallbackView, self).dispatch(request, *args, **kwargs)
if isinstance(res, HttpResponseRedirect) and res.url == settings.LOGIN_REDIRECT_URL:
Copy link
Collaborator

@gyusang gyusang Jan 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

페이스북은 우선 allauth에서 제공하는 providers로 작성해두었습니다. 상규님처럼 Custom Facebook 작성해보려고 하는데 Custom Google은 어떤 목적으로 작성되었던 건지 다시 한번 설명해주실 수 있을까요? 😄

@yuri-0415 Custom Google을 만든 것은, callback에서 로그인에 성공했을 때 response를 302 redirect 대신 200 ok로 바꾸고, 안에 user 정보와 토큰 정보를 포함하기 위함입니다.
또한 /accounts/google/login/을 요청했을 때에도 로그인 링크로 302 redirect되는 대신 url을 body에 포함한 200 ok가 됩니다. (API 문서를 참고해 주세요)

assert hasattr(request, 'user')
# login success
data = UserSerializer(instance=request.user).data
token, created = Token.objects.get_or_create(user=request.user)
data['token'] = token.key
res = Response(data=data)
else:
res = Response({
'error': 'An error occurred in social login.',
}, status=status.HTTP_400_BAD_REQUEST)
return api_view.render(res)


class TokenOAuth2LoginView(OAuth2LoginView):
def dispatch(self, request, *args, **kwargs):
api_view = SocialLoginView()
api_view.dispatch(request, *args, **kwargs)
res = super(TokenOAuth2LoginView, self).dispatch(request, *args, **kwargs)
if isinstance(res, HttpResponseRedirect) and res.url:
url = res.url
data = {
'url': url,
}
try:
queries = url.split('?')
queries = queries[1].split('&')
for query in queries:
if query[:6] == 'state=':
data['state'] = query[6:]
except:
pass
if 'state' not in data:
res = Response({
'error': 'An error occurred in social login.'
}, status=status.HTTP_400_BAD_REQUEST)
else:
res = Response(data)
else:
res = Response({
'error': 'An error occurred in social login.',
}, status=status.HTTP_400_BAD_REQUEST)
return api_view.render(res)


class GoogleOAuth2NoRedirectAdapter(GoogleOAuth2Adapter):
provider_id = GoogleProviderNoRedirect.id


oauth2_callback = TokenOAuth2CallbackView.adapter_view(GoogleOAuth2NoRedirectAdapter)
oauth2_login = TokenOAuth2LoginView.adapter_view(GoogleOAuth2NoRedirectAdapter)
Loading