I have started using https://github.com/omab/django-social-auth and been successfully able to login via twitter, google and facebook.
Needed
I need to query about the logged in user in order to do more things, which Model I shall be using for that?
I don't see any examples for that
Thank you
Update
#Omab, I did not understand how this would work, can you please help. When I login with twitter, the callback goes to following code
#login_required
def done(request):
"""Login complete view, displays user data"""
ctx = {
'version': version,
'last_login': request.session.get('social_auth_last_login_backend')
}
logging.warn('context - ' + str(ctx))
logging.warn('request - ' + str(request))
return render_to_response('home.html', ctx, RequestContext(request))
Can you tell me how can I access to user instance here?
Thank you
The app stores the social account details using the UserSocialAuth model, to retrieve any instance just do:
user.social_auth.filter(provider="...")
Where:
user is a User instance (request.user for current logged in user)
provider is a string with the provider name (facebook, twitter, etc)
The UserSocialAuth instance stores the needed tokens to call the needed API:
print user_social_auth.tokens
{...}
As suggested by K-man, you can try this (Identifying the backend provider of a logged in user):
request.user.social_auth.values_list('provider')
Other values that you can find in the values_list include: id, uid (for ex. facebook user id), user, extra_data (which contains the access_token)
Related
I spent some time reading through the documentation and forums, but not sure I understand this. I have this bit of code in the views of my app:
def billboard_index(request):
if request.method == 'POST':
form = SpotiForm(request.POST)
if form.is_valid():
date = form.cleaned_data['spotiread_date']
try:
url = 'https://www.billboard.com/charts/hot-100/' + date
billboard = requests.get(url)
billboard.raise_for_status()
except:
print("No response")
else:
soup = BeautifulSoup(billboard.text, 'html.parser')
positions = [int(i.text) for i in soup.find_all(name='span', class_='chart-element__rank__number')]
songs = [i.text for i in soup.find_all(name='span', class_='chart-element__information__song')]
artists = [i.text for i in soup.find_all(name='span', class_='chart-element__information__artist')]
top100 = list(zip(positions, songs, artists))
if Top100model.objects.exists():
Top100model.objects.all().delete()
for position in top100:
top100data = Top100model(
idtop=str(position[0]), artist=str(position[2]), song=str(position[1])
)
top100data.save()
params = {
'client_id': SPOTIPY_CLIENT_ID,
'response_type': 'code',
'redirect_uri': request.build_absolute_uri(reverse('spotiauth')),
'scope': 'playlist-modify-private'
}
query_string = urlencode(params)
url = '{}?{}'.format('https://accounts.spotify.com/authorize', query_string)
return redirect(to=url)
# if a GET (or any other method) we'll create a blank form
else:
form = SpotiForm()
return render(request, 'billboardapp.html', {'form': form})
on billboard_index I have a form with one field in which user puts a date. This date is then used as an input for a webscraper. I save the scraped data in the database, this works (I know this code will break in couple instances, but I'll deal with this later). Next I want to follow the spotify authorization flow, so I redirect to a url at spotify/authorization, it works. This gives me the code back when I'm redirected to spotiauth.html. At the same time, I print there all the database entries that were added during scraping. This is the spotiauth view:
def spotiauth(request):
Positions100 = Top100model.objects.all()
print(request)
context = {
'positions': Positions100,
}
return render(request, 'spotiauth.html', context=context)
I have couple questions:
How do I pass additional arguments to the spotiauth view? I tried
return redirect(to=url, date=date)
But I can't access it in spotiauth view. So I don't really want to pass it in the url, I just want it as an argument to another function, is this doable?
Is this the actual way to go about it? Not sure this is the simplest thing to do.
Thank you for your help!
Authentication is something that should be handled in a generic way, and not individually and explicitly per request. This is because you don't want to duplicate the authentication code in every request that needs authentication.
Lucky you, you are using Django which already comes with an authentication and authorization layer, and a great community that creates great libraries such as django-allauth that integrate OAuth2 authentication into Django's authentication layer.
OAuth2 against Spotify is what you are trying to implement here. Just
include django-allauth via pip,
configure the Spotify provider in the settings following their documentation,
include their URLs for login and registration (see their docs)
... and you should be able to sign into your app using a Spotify account.
For your regular views then, the decorator login_required would then suffice.
Django-allauth will do the following:
for users who sign in via OAuth2 providers, regular Django accounts will be created automatically
you can see these users in the Django admin, in the same list as the regular Django users
you can manage the configuration of the OAuth2 provider configuration via the Django Admin - django-allauth brings a model with an admin for it
django-allauth brings additional functionality like email verification, multiple email address management etc.
If you want to style the login and registration pages, you can implement your own templates using django-allauth's templates as basis.
Okay so, ordinary Django allows you to simply:
if request.user.is_authenticated:
I want to be able to do the same in Pyrebase. Have the views sort of already know which user has logged in based on the current session without having to sign the user in in all views.
I have tried:
def sign_in(request):
user = firebase.auth().sign_in_with_email_and_password('email', 'password')
user_token = firebase.auth().refresh(user['refreshToken']
request.session['session_id'] = user_token
I noticed this creates a session ID for me. But I don't know how to associate it with the current user and I know it has something to do with the refresh token.
If I don't check authentication, anyone can visit any page of my site without signing in.
On project I use django-rest-auth for user registration and authentication. Also i added code for facebook login:
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
from rest_auth.registration.views import SocialLoginView
class FacebookOAuth2AdapterFixed(FacebookOAuth2Adapter):
def __init__(self):
pass
class FacebookLogin(SocialLoginView):
adapter_class = FacebookOAuth2Adapter
And in my project urls.py I add
url(r'^rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login'),
But on url localhost:8000/rest-auth/facebook I see form with 2 parameters: Access token(already have) and code.
My question is next: Can I login via facebook without this code, and if not, how can I get this code without frontend? How can I check work user authentication/registration or not?
PS: SocialApp created, facebook app created, app id and app secret added to social app.
Only one of "Access Token" or "Code" field is required. (I have not tested the Code field but the Access Token field works, with the Code field left blank)
To use Access Token, after the user performs the "Login to Facebook" step on the client side using Facebook javascript SDK, you will receive a response from Facebook which includes "accessToken" for accessing data on Facebook. Simply paste this accessToken into the "Access Token" field and it will automatically login and/or create the user's account from data retrieved from Facebook.
Obviously you can then perform the same process by posting the access token to the form all in javascript.
In the field of Access Token, Pass the User Access Token that you will get from Facebook developer dashboard(generate and debug), code field you can leave as blank. It will create user in your application and will return JWT token with user details.
Is it possible to use Flask-Social and Flask-Security if I only want to use Facebook Login, for example, for user registration and login, i.e. no local registration/login forms?
I looked through the Flask-Social example application and documentation but couldn't tell if this is possible. In the example application, users cannot login with Facebook unless they've previously registered. After registering with the example application, they can associate their Facebook account with their local account.
When I tried to call social.facebook.get_connection() I got an AttributeError 'AnonymousUser' object has no attribute 'id' because there's no current_user, which is defined by flask-security after registration/login.
This is doable without too much extra work using the #login_failed.connect_via decorator. With app as your instance of a Flask app, it would look like
#login_failed.connect_via(app):
def on_login_failed(sender, provider, oauth_response):
connection_values = get_connection_values_from_oauth_response(provider, oauth_response)
ds = current_app.security.datastore
user = ds.create_user( ... ) #fill in relevant stuff here
ds.commit()
connection_values['user_id'] = user.id
connect_handler(connection_values, provider)
login_user(user)
db.commit()
return render_template('success.html')
As for filling in the relevant stuff for creating the user, I just create a random string for the password, and haven't had issues leaving the email null. I also just included the exact same answer on the Flask-Social github page.
i have an application where we allow users to use Oauth2 for authentication and even Custom User Registrations. All the Users are saved into the default User entity in the datastore. If the user is logging in using Oauth2 for the first time a new record in the default User entity is created like this:
"""Check if user is already logged in"""
if self.logged_in:
logging.info('User Already Logged In. Updating User Login Information')
u = self.current_user
u.auth_ids.append(auth_id)
u.populate(**self._to_user_model_attrs(data, self.USER_ATTRS[provider]))
u.put()
else:
"""Create a New User"""
logging.info('Creating a New User')
ok, user = self.auth.store.user_model.create_user(auth_id, **self._to_user_model_attrs(data, self.USER_ATTRS[provider]))
if ok:
self.auth.set_session(
self.auth.store.user_to_dict(user)
)
self.redirect(continue_url)
for custom registrations records are inserted through the following handler.
class RegistrationHandler(TemplateHandler, SimpleAuthHandler):
def get(self):
self.render('register.html')
def post(self):
"""Process registration form."""
user = 'appname:%s' % self.request.get('email')
name = '%s %s' % (self.request.get('first_name'), self.request.get('last_name'))
password = self.request.get('password')
avatar = self.request.get('avatar')
act_url = user_activation.Activate(self.request.get('first_name'), self.request.get('email'))
ok, user = User.create_user(auth_id=user, name=name, password_raw=password, email=self.request.get('email'))
if ok:
self.auth.set_session(self.auth.store.user_to_dict(user))
acc = models.Account(display_name=self.request.get('first_name'), act_url=act_url, act_key=act_url.split('activate/')[1], user=users.User(User.get_by_auth_id(self.current_user.auth_ids[0]).email))
acc.put()
if avatar:
avt = models.Picture(is_avatar=True, is_approved=True, image=avatar, user=users.User(User.get_by_auth_id(self.current_user.auth_ids[0]).email))
avt.put()
self.redirect('/')
Now we are using webapp2_extras.sessions for session handling. We have different models like, Comments, Images, Reviews etc in which we want to use db.UserProperty() as the author field. However, the author field shows blank or None whenever we enter a record into any of these models using 'users.get_current_user()'. I think this is because we are handling the sessions through webapp2 sessions.
What we want to achieve is to be able to use the db.UserProperty field in various models and link appropriately to the current user using webapp2 sessions ?
the UserProperty() has to be passed with a User Object in order for it to properly insert the records. Even though we are able to enter the records using the following code :
user = users.User(User.get_by_auth_id(self.current_user.auth_ids[0]).email)
or
user = users.User(User.get_by_auth_id(self.current_user.auth_ids[0]).name)
but then we are not able to get the whole user object by referencing to model.author
Any ideas how we should achieve this ?
OAuth 2.0 is not currently supported by Users service. Supported options are
Google Accounts
OpenId
OAuth 1.0
I don't frankly understand what you're trying to accomplish with introducing db.User in to the codebase. Given there's self.current_user, I assume you're already handling authentication process.
When you do self.auth.store.user_model.create_user - that already gives you a webapp2's user object/entity (it has nothing to do with db.User though). I believe that's what you'll have to use as your author field given OAuth 2.0 constraint.
users.get_current_user() relies on a special cookie (App Engine internal). In fact, it has nothing to do with webapp2's session (or any other "custom" session for that matter). You could hack it by setting the cookie to a value that App Engine internals can understand and be tricked as if a user were logged in with one of the methods I mentioned, but I wouldn't recommend this approach. It is not documented (cookie name, format, etc.) and might be changed at any time.
Instead of using UserProperty to store references to the webapp2 user objects, you should instead store the auth_id as a StringProperty and add a convenience method for fetching the corresponding webapp2 user entity.
Something like this
from webapp2_extras.appengine.auth.models import User
class Comment(db.model):
text = db.StringProperty()
author = db.StringProperty()
def get_author(self):
return User.get_by_auth_id(self.author)