django-allauth从iOS设备登录Facebook令牌 [英] django-allauth logging in with Facebook token from iOS Device
问题描述
我正在使用Facebook iOS SDK将Facebook访问令牌发布到我的Django服务器URI。相应的views.py函数如下所示,当我从iOS进行POST时,我收到了200个响应代码。但是,我有一个第二个@login_required装饰的URI,我从iOS设备立即呼叫,认为我没有登录,并将我重定向到我的主页。我究竟做错了什么?在iOS上成功POST之后,我如何保持登录?
I am using the Facebook iOS SDK to POST the Facebook Access Token to my Django server URI. The corresponding views.py function is shown below and I get a 200 Response code when I do the POST from iOS. However, I have a second @login_required decorated URI that I call from the iOS Device immediately afterword which considers me not logged in and redirects me to my main page. What am I doing wrong? How do I 'stay' logged in after my successful POST from iOS?
# For POSTing the facebook token
from django.views.decorators.csrf import csrf_exempt
from allauth.socialaccount import providers
from allauth.socialaccount.models import SocialLogin, SocialToken, SocialApp
from allauth.socialaccount.providers.facebook.views import fb_complete_login
from allauth.socialaccount.helpers import complete_social_login
# Log in from Facebook
@csrf_exempt
def mobile_facebook_login(request):
response = HttpResponse() ## Create an HTTP Response Object
if request.method == "POST": # The method better be a POST
access_token = request.POST.get('access_token') # Get token
try:
app = SocialApp.objects.get(provider="facebook")
token = SocialToken(app=app, token=access_token)
# Check token against facebook
login = fb_complete_login(request, app, token)
login.token = token
login.state = SocialLogin.state_from_request(request)
# Add or update the user into users table
ret = complete_social_login(request, login)
# If we get here we've succeeded
response['Auth-Response'] = 'success'
response.status_code = 200 # Set status
return response
except Exception,e:
# If we get here we've failed
response['Auth-Response'] = 'failure: %s'%(e)
response.status_code = 401 # Set status
return response
else:
# If we get here we've failed
response['Auth-Response'] = 'failure'
response.status_code = 401 # Set status
return response
======= UPD ATE ==========
======= UPDATE ==========
好的,谢谢你的意见。所以我现在也在POST电子邮件地址以及获取用户并手动登录。但是,后续请求STILL未通过身份验证。所以@login_required装饰器仍然失败..任何其他想法?
Ok, thanks for the comments. So I am now POSTing the facebook email address as well and getting the user and logging them in manually. However, subsequent requests STILL are not authenticated. So the @login_required decorator still fails.. Any other ideas?
# Log in from Facebook
@csrf_exempt
def mobile_facebook_login(request):
response = HttpResponse() ## Create an HTTP Response Object
if request.method == "POST": # The method better be a POST
access_token = request.POST.get('access_token') # Get token
email = request.POST.get('email') # Get email
try:
app = SocialApp.objects.get(provider="facebook")
token = SocialToken(app=app, token=access_token)
# Check token against facebook
login = fb_complete_login(request, app, token)
login.token = token
login.state = SocialLogin.state_from_request(request)
# Add or update the user into users table
ret = complete_social_login(request, login)
# Try to get username from email
try:
user = User.objects.get(email=email) # Get User
# Login the user from Django's perspective
user.backend = 'django.contrib.auth.backends.ModelBackend'
auth_login(request,user)
except User.DoesNotExist:
# If we get here we've failed
response['Auth-Response'] = 'failure: %s'%(e)
response.status_code = 401 # Set status
return response
# If we get here we've succeeded
response['Auth-Response'] = 'success'
response.status_code = 200 # Set status
return response
except Exception,e:
# If we get here we've failed
response['Auth-Response'] = 'failure: %s'%(e)
response.status_code = 401 # Set status
return response
else:
# If we get here we've failed
response['Auth-Response'] = 'failure'
response.status_code = 401 # Set status
return response
====另一个更新==========
==== Another Update ==========
根据这篇文章中的第二个答案:
没有密码的django认证
Based on the 2nd answer in this post: django authentication without a password
我创建了一个不需要的自定义登录后端一个密码该帖子中的第三个答案讨论了如何做到这一点:
I created a custom login backend that does not require a password. The 3rd answer in that post discusses how doing this:
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
不在会话中存储登录验证。所以我尝试使用自定义的后端。
Doesn't store the login validation in the session. So I tried using a custom backend.
这是我的修改后的代码:
Here is my modified code:
# Log in from Facebook
@csrf_exempt
def mobile_facebook_login(request):
response = HttpResponse() ## Create an HTTP Response Object
if request.method == "POST": # The method better be a POST
access_token = request.POST.get('access_token') # Get token
email = request.POST.get('email') # Get email
try:
app = SocialApp.objects.get(provider="facebook")
token = SocialToken(app=app, token=access_token)
# Check token against facebook
login = fb_complete_login(request, app, token)
login.token = token
login.state = SocialLogin.state_from_request(request)
# Add or update the user into users table
ret = complete_social_login(request, login)
# Try to get username from email
try:
user = User.objects.get(email=email) # Get User
# Login the user from Django's perspective
user.backend = 'django_tours.auth_backend.PasswordlessAuthBackend'
user = authenticate(email=user.email)
auth_login(request,user)
#request.session.cycle_key()
except User.DoesNotExist:
# If we get here we've failed
response['Auth-Response'] = 'failure: %s'%(e)
response.status_code = 401 # Set status
return response
# If we get here we've succeeded
response['Auth-Response'] = 'success'
response['User-Is-Authenticated'] = '%s'%(request.user.is_authenticated())
response.status_code = 200 # Set status
return response
except Exception,e:
# If we get here we've failed
response['Auth-Response'] = 'failure: %s'%(e)
response.status_code = 401 # Set status
return response
else:
# If we get here we've failed
response['Auth-Response'] = 'failure'
response.status_code = 401 # Set status
return response
使用hurl.it我得到这个HTTP 200的响应,但仍然没有考虑从iPhone登录:
Using hurl.it I get this HTTP 200 response, but am still NOT considered logged in from the iPhone:
Auth-Response: success
Content-Encoding: gzip
Content-Length: 20
Content-Type: text/html; charset=utf-8
Date: Thu, 08 May 2014 00:22:47 GMT
Server: Apache/2.2.22 (Ubuntu)
Set-Cookie: csrftoken=UuJDP6OB3YCSDtXLEa10MgJ70tDtIfZX; expires=Thu, 07-May-2015 00:22:48 GMT; Max-Age=31449600; Path=/, sessionid=kdr061v1pcsbqtvgsn3pyyqj9237z6k8; expires=Thu, 22-May-2014 00:22:48 GMT; httponly; Max-Age=1209600; Path=/, messages="4f919699a4730a3df220a0eb3799ed59d2756825$[[\"__json_message\"\0540\05425\054\"Successfully signed in as philbot.\"]]"; Path=/
User-Is-Authenticated: True
Vary: Cookie,Accept-Encoding
推荐答案
感谢所有的帮助和输入 - 我终于解决了。我不知道为什么用Facebook登录cookies的确切根本原因是cookies和标准登录工作正常。我注意到从Facebook登录返回的cookie的域被格式化为一个领先的。像这样:
Thanks for all the help and input -- I finally solved it. I don't know the exact root cause of why logging in with Facebook munged the cookies and standard login worked fine. I did notice that the domain of the cookies returned from the Facebook login were formatted with a leading "." like this:
[ .domain.com ]
虽然工作的标准登录名有这样的cookie域:
Whereas the standard login that worked had cookie domains like this:
[ www.domain.com ]
在使用Facebook成功登录并存储后,我从HTTP响应中分析了Cookie他们在单身中:
I parsed the cookies from the HTTP response after successfully logging in with Facebook and stored them in the singleton:
// Extract cookie information
NSRange range = [cookieString rangeOfString:@"csrftoken="];
if (range.location!=NSNotFound){
cookieString = [cookieString substringFromIndex:NSMaxRange(range)];
range = [cookieString rangeOfString:@";"];
if (range.location!=NSNotFound){
self.appDelegate.djangoCsrftoken = [cookieString substringToIndex:range.location];
}
}
range = [cookieString rangeOfString:@"sessionid="];
if (range.location!=NSNotFound){
cookieString = [cookieString substringFromIndex:NSMaxRange(range)];
range = [cookieString rangeOfString:@";"];
if (range.location!=NSNotFound){
self.appDelegate.djangoSessionId = [cookieString substringToIndex:range.location];
}
}
if (LOGIN_DEBUG) { // Debug the response
NSLog(@"Extracted csrftoken is: %@",self.appDelegate.djangoCsrftoken);
NSLog(@"Extracted sessionid is: %@",self.appDelegate.djangoSessionId);
}
然后,为以下请求明确创建了这些cookie:
I then, created those cookies explicitly for the following request:
// Clear all cookies when app launches
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *each in cookieStorage.cookies) {
//if ( [each.domain isEqualToString:DOMAIN] ) {
NSLog(@"Deleting cookie: %@ -- %@",each.name,each.domain);
[cookieStorage deleteCookie:each];
//}
}
//////////////// CSRF TOKEN /////////////////////
// Create cookies based on parsed values
NSMutableDictionary *cookieCsrfProperties = [NSMutableDictionary dictionary];
[cookieCsrfProperties setObject:@"csrftoken" forKey:NSHTTPCookieName];
[cookieCsrfProperties setObject:self.appDelegate.djangoCsrftoken forKey:NSHTTPCookieValue];
[cookieCsrfProperties setObject:DOMAIN forKey:NSHTTPCookieDomain];
[cookieCsrfProperties setObject:DOMAIN forKey:NSHTTPCookieOriginURL];
[cookieCsrfProperties setObject:@"/" forKey:NSHTTPCookiePath];
[cookieCsrfProperties setObject:@"0" forKey:NSHTTPCookieVersion];
// Set expiration to one month from now or any NSDate of your choosing
// this makes the cookie sessionless and it will persist across web sessions and app launches
/// if you want the cookie to be destroyed when your app exits, don't set this
[cookieCsrfProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
NSHTTPCookie *csrfCookie = [NSHTTPCookie cookieWithProperties:cookieCsrfProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:csrfCookie];
//////////////// SessionId TOKEN /////////////////////
// Create cookies based on parsed values
NSMutableDictionary *cookieSessionIdProperties = [NSMutableDictionary dictionary];
[cookieSessionIdProperties setObject:@"sessionid" forKey:NSHTTPCookieName];
[cookieSessionIdProperties setObject:self.appDelegate.djangoSessionId forKey:NSHTTPCookieValue];
[cookieSessionIdProperties setObject:DOMAIN forKey:NSHTTPCookieDomain];
[cookieSessionIdProperties setObject:DOMAIN forKey:NSHTTPCookieOriginURL];
[cookieSessionIdProperties setObject:@"/" forKey:NSHTTPCookiePath];
[cookieSessionIdProperties setObject:@"0" forKey:NSHTTPCookieVersion];
// Set expiration to one month from now or any NSDate of your choosing
// this makes the cookie sessionless and it will persist across web sessions and app launches
/// if you want the cookie to be destroyed when your app exits, don't set this
[cookieCsrfProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
NSHTTPCookie *sessionIdCookie = [NSHTTPCookie cookieWithProperties:cookieSessionIdProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:sessionIdCookie];
///////////////////////////////////////////////////
// Create request
NSURL *url = [NSURL URLWithString:requestUrl];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
urlRequest.HTTPShouldHandleCookies = YES;
NSHTTPCookie *setCookie;
for (setCookie in [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies) {
if ( ([setCookie.name isEqualToString:@"csrftoken" ] || [setCookie.name isEqualToString:@"sessionid"]) ) {
NSLog(@"Adding Cookie: %@ = %@ [ %@ ]", setCookie.name, setCookie.value, setCookie.domain);
[urlRequest addValue:setCookie.value forHTTPHeaderField:setCookie.name];
}
}
NSURLResponse *response = nil;
NSError * error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
完成后,我可以使用Django-allauth成功登录Facebook。
After doing that, I could successfully login with Facebook using Django-allauth.
这篇关于django-allauth从iOS设备登录Facebook令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!