我正在用API后端(用DRF构建)和angularjs客户端构建django应用程序。我的目标是使用JWT代替会话,使服务器和客户端完全解耦。我正在尝试将python-社会-auth(PSA)与django-rest-框架-jwt(DRFJWT)集成,因此我的目标是在这方面有一个流程:
用户通过棱角客户端->客户端登录电子邮件/facebook到PSA的url -> PSA登录/创建用户->!DRFJWT创建令牌,然后发送回客户端->客户端,将令牌存储在本地存储中,然后使用每个请求的令牌。
!:这是我现在挣扎的地方。我的想法是可以像这样修改PSA中的完成方法。
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler
def do_complete(backend, login, user=None, redirect_name='next',
*args, **kwargs):
# pop redirect value before the session is trashed on login()
data = backend.strategy.request_data()
redirect_value = backend.strategy.session_get(redirect_name, '') or \
data.get(redirect_name, '')
is_authenticated = user_is_authenticated(user)
user = is_authenticated and user or None
partial = partial_pipeline_data(backend, user, *args, **kwargs)
if partial:
xargs, xkwargs = partial
user = backend.continue_pipeline(*xargs, **xkwargs)
else:
user = backend.complete(user=user, *args, **kwargs)
if user_is_active(user):
# catch is_new/social_user in case login() resets the instance
is_new = getattr(user, 'is_new', False)
social_user = user.social_user
login(backend, user, social_user)
payload = jwt_payload_handler(user)
return { 'token': jwt_encode_handler(payload) }这是我想要完成的唯一方法吗?
我还想知道,从最佳实践的角度来看,使用会话来管理管道和用于auth的JWT是否还行?
发布于 2015-01-29 21:37:32
我还使用python-社会-auth和django-rest-框架-jwt进行用户身份验证。
我能够将这两个身份验证系统集成在一起的方式是创建一个自定义视图,该视图接受oAuth提供程序提供的oAuth,并尝试使用它创建一个新用户。创建用户后,我将返回JWT令牌,而不是返回经过身份验证的用户/会话。
下面的代码片段解释了解决方案。
后端
在我的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()),
...
)前端
现在后端身份验证已经连接好了,您可以使用任何前端库发送access_token并对用户进行身份验证。在我的例子中,我使用了AngularJS。
在控制器文件中,我调用API如下所示:
/**
* This function gets called after successfully getting the access_token from Facebook's 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框架-jwt,尽管用户仍然可以使用Facebook、Google、Twitter等网站提供的令牌进行身份验证。
我只展示了通过Facebook进行身份验证的方法,但是对于其他提供商,您可以采用类似的方法。
发布于 2015-02-14 15:01:54
不,您不需要在python-social-auth中使用会话(标准Django登录系统)。您需要让JWT和PSA一起工作的是DRF。
这是我的解决方案:
我使用标准PSA的url来提出过于社会化的/login/(?P<backend>[^/]+)/$请求,更改了urls.py中的url以匹配从Facebook/Twitter重定向到我自己的。
url(r'^complete/(?P<backend>[^/]+)/$', views.SocialAuthViewComplete.as_view()),使用API的目的是在PSA正在执行的请求中访问用户数据。如果您在DEFAULT_AUTHENTICATION_CLASSES中具有JWT身份验证,DRF允许您这样做。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),}在views.py
from social.apps.django_app.views import complete
class SocialAuthViewComplete(APIView):
permission_classes = ()
def post(self, request, backend, *args, **kwargs):
try:
#Wrap up PSA's `complete` method.
authentication = complete(request, backend, *args, **kwargs)
except Exception, e:
exc = {
'error': str(e)
}
return Response(exc, status=status.HTTP_400_BAD_REQUEST)
return Response({'data': authentication}, status=status.HTTP_202_ACCEPTED)然后,我修改了--PSA中的do_complete方法:
def do_complete(backend, login, user=None, redirect_name='next',
*args, **kwargs):
# pop redirect value before the session is trashed on login()
data = backend.strategy.request_data()
redirect_value = backend.strategy.session_get(redirect_name, '') or \
data.get(redirect_name, '')
is_authenticated = user_is_authenticated(user)
user = is_authenticated and user or None
partial = partial_pipeline_data(backend, user, *args, **kwargs)
if partial:
xargs, xkwargs = partial
user = backend.continue_pipeline(*xargs, **xkwargs)
else:
user = backend.complete(user=user, *args, **kwargs)
user_model = backend.strategy.storage.user.user_model()
if user and not isinstance(user, user_model):
return user
if is_authenticated:
if not user:
information = 'setting_url(backend, redirect_value, LOGIN_REDIRECT_URL'
else:
information = 'setting_url(backend, redirect_value, NEW_ASSOCIATION_REDIRECT_URL,LOGIN_REDIRECT_URL'
elif user:
# Get the JWT payload for the user.
payload = jwt_payload_handler(user)
if user_is_active(user):
is_new = getattr(user, 'is_new', False)
if is_new:
information = 'setting_url(backend, NEW_USER_REDIRECT_URL, redirect_value, LOGIN_REDIRECT_URL'
else:
information = 'setting_url(backend, redirect_value, LOGIN_REDIRECT_URL'
else:
return Response({
'status': 'Unauthorized',
'message': 'The user account is disabled.'
}, status=status.HTTP_401_UNAUTHORIZED)
else:
information = 'setting_url(backend, LOGIN_ERROR_URL, LOGIN_URL'
return { 'an information i may use in future': information,
'token': jwt_encode_handler(payload) # Create the response object with the JWT payload.
}我尝试了管道和用户关联,它正确地工作。此外,如果需要使用JWT,则始终可以修改PSA中的另一个方法。
https://stackoverflow.com/questions/26824019
复制相似问题