give openid users additional information

2019-02-23 02:07发布

So I am writing an app in python for google appengine on the jinja2 templating platform. I have gotten OpenID to work just fine on my site and it allows the user to login and I can display their email/ID up in the top right corner.

Now I want users to have their own usernames and be able to store some additional data about them such as site visits and certain posts to areas of the site.

I know I need to create a table in the database with users and everything but what is the correct way to do this with OpenID. I want to automatically create the user when someone logs in for the first time but I am not quite sure how to do this efficiently. I think I can manage it by redirecting them to a page after login that checks their federated_identity in a database and if it exists there already it just redirects them on to the home page but if not it creates a new user.

Is there a more efficient way so that I am not querying the database everytime someone logs in or is that a pretty decent way to do it?

1条回答
Bombasti
2楼-- · 2019-02-23 02:33

You are right, you have to create your own User model and store the extra information and whatever business logic you have in your application. All you have to do is to store something unique (federated_id for example) along with the extra username, name, etc.

After logging in with the OpenID, you will check if that particular federated_id is in your datastore and you will return that particular user_db, or create a new one with default values and return the newly created user_db.

The important thing is that in your requests you will always deal with your own user_db entity and not the users.get_current_user() because this is basically read only and limited.

Here is a full example, that also demonstrates a base handler class with the get_user() function that will return your own user_db entity if the user is logged in and None otherwise. If the user is going to login for the first time, a new user_db entity is created with some default values (name, username, email, admin, federated_id):

from google.appengine.api import users
from google.appengine.ext import ndb
import webapp2

class User(ndb.Model):
  name = ndb.StringProperty(required=True)
  username = ndb.StringProperty(required=True)
  email = ndb.StringProperty()
  federated_id = ndb.StringProperty()
  admin = ndb.BooleanProperty()

class BaseHandler(webapp2.RequestHandler):
  def get_user_db(self):
    federated_user = users.get_current_user()
    if not federated_user:
      return None
    user_db_qry = User.query(User.federated_id == federated_user.user_id())
    user_db_list = user_db_qry.fetch(1)
    #If that returns non empty list, then return the first element which is the user_db
    if user_db_list:
      return user_db_list[0]

    #Otherwise create a new user_db entity, with default values and return
    user_db = User(
        name=federated_user.nickname().title(),
        username=federated_user.nickname(),
        email=federated_user.email(),
        federated_id=federated_user.user_id(),
        admin=users.is_current_user_admin(),
      )
    user_db.put()
    return user_db

class MainHandler(BaseHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/html'
    if self.get_user_db():
      self.response.out.write('Hello, %s!</br>' % self.get_user_db().name)
      self.response.out.write('<a href="%s">Logout</a>' % (users.create_logout_url(self.request.uri)))
    else:
      self.response.out.write('Hello, stranger!<br>')
      self.response.out.write('<a href="%s">Login</a>' % (users.create_login_url(self.request.uri)))

app = webapp2.WSGIApplication([('/', MainHandler)],
                              debug=True)

There are many different approaches to this problem, but I think this is a good start to get the idea.

查看更多
登录 后发表回答