为已创建的 Webapp2 User 模型添加用户名属性 (与 Simpleauth 结合使用)

30 阅读2分钟

我目前正在使用 Python/App Engine/SimpleAuth 为我的应用程序提供 OAuth 登录。当前的工作流程是,用户使用 OAuth 登录,稍后他们可以在应用程序中为自己创建唯一的用户名。

在 Webapp2 User 实体已经创建后,我在创建唯一用户名时遇到了问题。我注意到 Webapp2 模型中有一种方式可以在应用程序实体组内启用唯一用户名,但我不知道如何为自己设置它。(我正在使用 SimpleAuth 为其他 OAuth 提供商设置所有内容。)

我想检查用户提交的“用户名”是否存在,如果不存在,则将其添加为当前登录用户的属性。感谢您对此提供的任何帮助/建议!

  1. 解决方案

您可以扩展 webapp2_extras.appengine.auth.models.User 并添加用户名属性,例如:

from webapp2_extras.appengine.auth.models import User as Webapp2User

class User(Webapp2User):
    username = ndb.StringProperty(required=True)

然后,要在创建 Webapp2 应用程序时需要一个包含此项的配置:

APP_CFG = {
    'webapp2_extras.auth': {
        'user_model': User,  # default is webapp2_extras.appengine.auth.models.User
        'user_attributes': ['username']  # list of User model properties
    }
}

app = webapp2.WSGIApplication(config=APP_CFG)

有了上面的配置,使用以下代码创建新用户将确保用户名是唯一的(由 Unique 模型确保):

auth_id = 'some-auth-id'  # e.g. 'google:123456789', see simpleauth example.
ok, props = User.create_user(auth_id, unique_properties=['username'],
                                    username='some-username',
                                    ...)
if not ok:
    # props list will contain 'username', indicating that
    # another entity with the same username already exists
    ...

问题是,使用此配置,您必须在创建时设置用户名。

如果您想使用户名可选,或者让用户稍后设置/更改它,您可能需要将上述代码更改为如下内容:

class User(Webapp2User):
    username = ndb.StringProperty()  # note, there's no required=True

# when creating a new user:
auth_id = 'some-auth-id'  # e.g. 'google:123456789', see simpleauth example.
ok, props = User.create_user(auth_id, unique_properties=[], ...)

基本上,unique_properties 将是空列表(或者您可以跳过它)。另外,您可以暂时将用户名属性分配给类似于 user.key.id() 的内容,直到用户决定将他们的用户名更改为更有意义的内容。例如,Google+ 个人资料链接:我当前的链接是 plus.google.com/11451798382… plus.google.com/+IamNotANum… 的内容。

然后,在“更改/设置用户名”表单处理程序中,您可以在用户名已经存在时检查它,并在没有用户名时更新 User 实体:

def handle_change_username(self):
    user = ...  # get the user who wants to change their username
    username = self.request.get('username')
    uniq = 'User.username:%s' % username
    ok = User.unique_model.create(uniq)
    if ok:
        user.username = username
        user.put()
    else:
        # notify them that this username
        # is already taken
        ...

User.unique_model.create(uniq) 将使用指定的值创建一个 Unique 实体,如果该值不存在。在这种情况下,ok 将为 True。否则,ok 将为 False,这表示具有该值(在本例中为唯一用户名)的实体已经存在。

另外,您可能希望将 User.unique_model.create() 和 user.put() 放在同一事务中(它将是 XG,因为它们位于不同的实体组中)。

希望对您有所帮助!