Ответ 1
Я также использую python-social-auth и django-rest-framework-jwt для аутентификации пользователей.
То, как мне удалось объединить две системы аутентификации, было создание пользовательского представления, которое принимает " access_token", предоставляемый поставщиком oAuth, и пытается создать с ним нового пользователя. После создания пользователя вместо возвращения аутентифицированного пользователя/сеанса я возвращаю токен JWT.
Ниже описаны фрагменты кода.
Back-End
В моем файле views.py я включил следующее:
@psa()
def auth_by_token(request, backend):
"""Decorator that creates/authenticates a user with an access_token"""
token = request.DATA.get('access_token')
user = request.user
user = request.backend.do_auth(
access_token=request.DATA.get('access_token')
)
if user:
return user
else:
return None
class FacebookView(views.APIView):
"""View to authenticate users through Facebook."""
permission_classes = (permissions.AllowAny,)
def post(self, request, format=None):
auth_token = request.DATA.get('access_token', None)
backend = request.DATA.get('backend', None)
if auth_token and backend:
try:
# Try to authenticate the user using python-social-auth
user = auth_by_token(request, backend)
except Exception,e:
return Response({
'status': 'Bad request',
'message': 'Could not authenticate with the provided token.'
}, status=status.HTTP_400_BAD_REQUEST)
if user:
if not user.is_active:
return Response({
'status': 'Unauthorized',
'message': 'The user account is disabled.'
}, status=status.HTTP_401_UNAUTHORIZED)
# This is the part that differs from the normal python-social-auth implementation.
# Return the JWT instead.
# Get the JWT payload for the user.
payload = jwt_payload_handler(user)
# Include original issued at time for a brand new token,
# to allow token refresh
if api_settings.JWT_ALLOW_REFRESH:
payload['orig_iat'] = timegm(
datetime.utcnow().utctimetuple()
)
# Create the response object with the JWT payload.
response_data = {
'token': jwt_encode_handler(payload)
}
return Response(response_data)
else:
return Response({
'status': 'Bad request',
'message': 'Authentication could not be performed with received data.'
}, status=status.HTTP_400_BAD_REQUEST)
В моем urls.py я включил следующий маршрут:
urlpatterns = patterns('',
...
url(r'^api/v1/auth/facebook/', FacebookView.as_view()),
...
)
Front-End
Теперь, когда аутентификация по серверу подключена, вы можете использовать любую библиотеку интерфейса для отправки access_token и аутентификации пользователя. В моем случае я использовал AngularJS.
В файле контроллера я вызываю API так:
/**
* This function gets called after successfully getting the access_token from Facebook API.
*/
function successLoginFbFn(response) {
var deferred = $q.defer();
$http.post('/api/v1/auth/facebook/', {
"access_token": response.authResponse.accessToken,
"backend": "facebook"
}).success(function(response, status, headers, config) {
// Success
if (response.token) {
// Save the token to localStorage and redirect the user to the front-page.
Authentication.setToken(response.token);
window.location = '/';
}
deferred.resolve(response, status, headers, config);
}).error(function(response, status, headers, config) {
// Error
console.error('Authentication error.');
deferred.reject(response, status, headers, config);
});
}
При таком подходе вы можете смешивать два плагина. Все отправленные токены будут поступать из django-rest-framework-jwt, хотя пользователи все равно могут аутентифицироваться с помощью тех, которые предоставляются сайтами, такими как Facebook, Google, Twitter и т.д.
Я только показал подход к аутентификации через Facebook, однако вы можете следовать аналогичному подходу для других поставщиков.