use*_*986 22 google-app-engine oauth-2.0 google-cloud-endpoints
有人可以解释与其他OAuth2提供商实施登录过程的步骤此链接Google Cloud Endpoints与另一个oAuth2提供商提供的关于编写自定义身份验证的信息很少,但我想对于像我这样的初学者来说还不够,请详细说明.特别是对Facebook感兴趣.
Pau*_*ulR 20
您需要根据他们的文档以及您将客户端应用程序部署到的环境(浏览器vs iOS与Android)实施Facebook的客户端API.这包括向他们注册您的应用程序.您注册的应用程序将指导用户完成身份验证流程,最后您的客户端应用程序将可以访问短期访问令牌.Facebook有多种类型的访问令牌,但是你感兴趣的那种称为用户访问令牌,因为它识别了授权用户.
通过字段或标头将访问令牌传递到您的Cloud Endpoints API.在您的API代码内部接收访问令牌并实施Facebook的API,以检查访问令牌的有效性.关于这个问题的第一个答案使它看起来很容易,但你可能想再次引用他们的文档.如果该检查通过,那么您将运行您的API代码,否则抛出异常.
您通常还希望实现一种缓存机制,以防止为每个Cloud Endpoints请求调用Facebook服务器端验证API.
最后,我提到您的客户端应用程序有一个短期令牌.如果您有一个基于浏览器的客户端应用程序,那么您可能希望将其升级为长期令牌.Facebook也有这样的流程,其中涉及您的API代码请求具有短期存在的长期令牌.然后,您需要将该长期令牌转移回客户端应用程序,以用于将来的Cloud Endpoints API调用.
如果您的客户端应用程序是基于iOS或Android的,则您的令牌由Facebook代码管理,您只需在需要时从相应的API请求访问令牌.
所以我实际上试图实现自定义身份验证流程.虽然可能会在安全方面进一步考虑,但似乎工作正常.
首先,用户转到我的应用程序并通过Facebook进行身份验证,应用程序获得了他的user_id和access_token.然后,应用程序使用这些信息调用auth API到服务器.
class AuthAPI(remote.Service):
@classmethod
def validate_facebook_user(cls, user_id, user_token):
try:
graph = facebook.GraphAPI(user_token)
profile = graph.get_object("me", fields='email, first_name, last_name, username')
except facebook.GraphAPIError, e:
return (None, None, str(e))
if (profile is not None):
# Check if match user_id
if (profile.get('id', '') == user_id):
# Check if user exists in our own datastore
(user, token) = User.get_by_facebook_id(user_id, 'auth', user_token)
# Create new user if not
if user is None:
#print 'Create new user'
username = profile.get('username', '')
password = security.generate_random_string(length=20)
unique_properties = ['email_address']
if (username != ''):
(is_created, user) = User.create_user(
username,
unique_properties,
email_address = profile.get('email', ''),
name = profile.get('first_name', ''),
last_name = profile.get('last_name', ''),
password_raw = password,
facebook_id = user_id,
facebook_token = user_token,
verified=False,
)
if is_created==False:
return (None, None, 'Cannot create user')
token_str = User.create_auth_token(user.get_id())
#print (user, token_str)
# Return if user exists
if token is not None:
return (user, token.token, 'Successfully logged in')
else:
return (None, None, 'Invalid token')
return (None, None, 'Invalid facebook id and token')
# Return a user_id and token if authenticated successfully
LOGIN_REQ = endpoints.ResourceContainer(MessageCommon,
type=messages.StringField(2, required=True),
user_id=messages.StringField(3, required=False),
token=messages.StringField(4, required=False))
@endpoints.method(LOGIN_REQ, MessageCommon,
path='login', http_method='POST', name='login')
def login(self, request):
type = request.type
result = MessageCommon()
# TODO: Change to enum type if we have multiple auth ways
if (type == "facebook"):
# Facebook user validation
user_id = request.user_id
access_token = request.token
(user_obj, auth_token, msg) = self.validate_facebook_user(user_id, access_token)
# If we can get user data
if (user_obj is not None and auth_token is not None):
print (user_obj, auth_token)
result.success = True
result.message = msg
result.data = json.dumps({
'user_id': user_obj.get_id(),
'user_token': auth_token
})
# If we cannot
else:
result.success = False
result.message = msg
return result
Run Code Online (Sandbox Code Playgroud)
除此之外,您可能还需要按照以下说明实现普通用户身份验证流程:http://blog.abahgat.com/2013/01/07/user-authentication-with-webapp2-on-google-app-engine /.
这是因为我获得的user_id和user_token是由webapp2_extras.appengine.auth提供的.
User.get_by_facebook_id的实现:
class User(webapp2_extras.appengine.auth.models.User):
@classmethod
def get_by_facebook_id(cls, fb_id, subj='auth', fb_token=""):
u = cls.query(cls.facebook_id==fb_id).get()
if u is not None:
user_id = u.key.id()
# TODO: something better here, now just append the facebook_token to a prefix
token_str = "fbtk" + str(fb_token)
# get this token if it exists
token_key = cls.token_model.get(user_id, subj, token_str)
print token_key, fb_token
if token_key is None:
# return a token that created from access_token string
if (fb_token == ""):
return (None, None)
else:
token = cls.token_model.create(user_id, subj, token_str)
else:
token = token_key
return (u, token)
return (None, None)
Run Code Online (Sandbox Code Playgroud)
服务器验证用户是否再次使用facebook进行身份验证.如果它通过,则认为用户已登录.在这种情况下,服务器从我们的数据存储区传回user_token(基于facebook_token生成)和user_id.
任何进一步的API调用都应使用此user_id和user_token
def get_request_class(messageCls):
return endpoints.ResourceContainer(messageCls,
user_id=messages.IntegerField(2, required=False),
user_token=messages.StringField(3, required=False))
def authenticated_required(endpoint_method):
"""
Decorator that check if API calls are authenticated
"""
def check_login(self, request, *args, **kwargs):
try:
user_id = request.user_id
user_token = request.user_token
if (user_id is not None and user_token is not None):
# Validate user
(user, timestamp) = User.get_by_auth_token(user_id, user_token)
if user is not None:
return endpoint_method(self, request, user, *args, **kwargs )
raise endpoints.UnauthorizedException('Invalid user_id or access_token')
except:
raise endpoints.UnauthorizedException('Invalid access token')
@endpoints.api(name='blah', version='v1', allowed_client_ids = env.CLIENT_IDS, auth=AUTH_CONFIG)
class BlahApi(remote.Service):
# Add user_id/user_token to the request
Blah_Req = get_request_class(message_types.VoidMessage)
@endpoints.method(Blah_Req, BlahMessage, path='list', name='list')
@authenticated_required
def blah_list(self, request, user):
newMessage = BlahMessage(Blah.query().get())
return newMessage
Run Code Online (Sandbox Code Playgroud)
注意:
| 归档时间: |
|
| 查看次数: |
6866 次 |
| 最近记录: |