当前位置: 首页 > 面试题库 >

Google Cloud端点的自定义身份验证(而不是OAuth2)

欧阳哲
2023-03-14
问题内容

我们对App Engine对Google Cloud
Endpoints
的支持感到非常兴奋。

也就是说,我们目前尚未使用OAuth2,通常会使用用户名/密码对用户进行身份验证,因此我们可以为没有Google帐户的客户提供支持。

由于我们免费获得了所有好处(API控制台,客户端库,健壮性,…),因此我们希望将API迁移到Google Cloud
Endpoints,但是我们的主要问题是……

如何向云端点添加自定义身份验证,我们以前在现有API中检查了有效的用户会话+ CSRF令牌。

有没有一种优雅的方法可以在不向protoRPC消息添加会话信息和CSRF令牌之类的东西的情况下做到这一点?


问题答案:

我正在为整个应用html" target="_blank">程序使用webapp2身份验证系统。因此,我尝试将其重新用于Google Cloud身份验证,然后知道了!

webapp2_extras.auth使用webapp2_extras.sessions存储身份验证信息。而且,该会话可以以3种不同的格式存储:securecookie,数据存储或内存缓存。

Securecookie是我正在使用的默认格式。我认为它非常安全,因为webapp2 auth系统已用于生产环境中运行的许多GAE应用程序

因此,我解码了这个securecookie并从GAE端点重用了它。我不知道这是否会产生一些安全问题(我希望不是),但也许@bossylobster可以说看安全方面是否可以。

我的Api:

import Cookie
import logging
import endpoints
import os
from google.appengine.ext import ndb
from protorpc import remote
import time
from webapp2_extras.sessions import SessionDict
from web.frankcrm_api_messages import IdContactMsg, FullContactMsg, ContactList, SimpleResponseMsg
from web.models import Contact, User
from webapp2_extras import sessions, securecookie, auth
import config

__author__ = 'Douglas S. Correa'

TOKEN_CONFIG = {
    'token_max_age': 86400 * 7 * 3,
    'token_new_age': 86400,
    'token_cache_age': 3600,
}

SESSION_ATTRIBUTES = ['user_id', 'remember',
                      'token', 'token_ts', 'cache_ts']

SESSION_SECRET_KEY = '9C3155EFEEB9D9A66A22EDC16AEDA'


@endpoints.api(name='frank', version='v1',
               description='FrankCRM API')
class FrankApi(remote.Service):
    user = None
    token = None

    @classmethod
    def get_user_from_cookie(cls):
        serializer = securecookie.SecureCookieSerializer(SESSION_SECRET_KEY)
        cookie_string = os.environ.get('HTTP_COOKIE')
        cookie = Cookie.SimpleCookie()
        cookie.load(cookie_string)
        session = cookie['session'].value
        session_name = cookie['session_name'].value
        session_name_data = serializer.deserialize('session_name', session_name)
        session_dict = SessionDict(cls, data=session_name_data, new=False)

        if session_dict:
            session_final = dict(zip(SESSION_ATTRIBUTES, session_dict.get('_user')))
            _user, _token = cls.validate_token(session_final.get('user_id'), session_final.get('token'),
                                               token_ts=session_final.get('token_ts'))
            cls.user = _user
            cls.token = _token

    @classmethod
    def user_to_dict(cls, user):
        """Returns a dictionary based on a user object.

        Extra attributes to be retrieved must be set in this module's
        configuration.

        :param user:
            User object: an instance the custom user model.
        :returns:
            A dictionary with user data.
        """
        if not user:
            return None

        user_dict = dict((a, getattr(user, a)) for a in [])
        user_dict['user_id'] = user.get_id()
        return user_dict

    @classmethod
    def get_user_by_auth_token(cls, user_id, token):
        """Returns a user dict based on user_id and auth token.

        :param user_id:
            User id.
        :param token:
            Authentication token.
        :returns:
            A tuple ``(user_dict, token_timestamp)``. Both values can be None.
            The token timestamp will be None if the user is invalid or it
            is valid but the token requires renewal.
        """
        user, ts = User.get_by_auth_token(user_id, token)
        return cls.user_to_dict(user), ts

    @classmethod
    def validate_token(cls, user_id, token, token_ts=None):
        """Validates a token.

        Tokens are random strings used to authenticate temporarily. They are
        used to validate sessions or service requests.

        :param user_id:
            User id.
        :param token:
            Token to be checked.
        :param token_ts:
            Optional token timestamp used to pre-validate the token age.
        :returns:
            A tuple ``(user_dict, token)``.
        """
        now = int(time.time())
        delete = token_ts and ((now - token_ts) > TOKEN_CONFIG['token_max_age'])
        create = False

        if not delete:
            # Try to fetch the user.
            user, ts = cls.get_user_by_auth_token(user_id, token)
            if user:
                # Now validate the real timestamp.
                delete = (now - ts) > TOKEN_CONFIG['token_max_age']
                create = (now - ts) > TOKEN_CONFIG['token_new_age']

        if delete or create or not user:
            if delete or create:
                # Delete token from db.
                User.delete_auth_token(user_id, token)

                if delete:
                    user = None

            token = None

        return user, token

    @endpoints.method(IdContactMsg, ContactList,
                      path='contact/list', http_method='GET',
                      name='contact.list')
    def list_contacts(self, request):

        self.get_user_from_cookie()

        if not self.user:
            raise endpoints.UnauthorizedException('Invalid token.')

        model_list = Contact.query().fetch(20)
        contact_list = []
        for contact in model_list:
            contact_list.append(contact.to_full_contact_message())

        return ContactList(contact_list=contact_list)

    @endpoints.method(FullContactMsg, IdContactMsg,
                      path='contact/add', http_method='POST',
                      name='contact.add')
    def add_contact(self, request):
        self.get_user_from_cookie()

        if not self.user:
           raise endpoints.UnauthorizedException('Invalid token.')


        new_contact = Contact.put_from_message(request)

        logging.info(new_contact.key.id())

        return IdContactMsg(id=new_contact.key.id())

    @endpoints.method(FullContactMsg, IdContactMsg,
                      path='contact/update', http_method='POST',
                      name='contact.update')
    def update_contact(self, request):
        self.get_user_from_cookie()

        if not self.user:
           raise endpoints.UnauthorizedException('Invalid token.')


        new_contact = Contact.put_from_message(request)

        logging.info(new_contact.key.id())

        return IdContactMsg(id=new_contact.key.id())

    @endpoints.method(IdContactMsg, SimpleResponseMsg,
                      path='contact/delete', http_method='POST',
                      name='contact.delete')
    def delete_contact(self, request):
        self.get_user_from_cookie()

        if not self.user:
           raise endpoints.UnauthorizedException('Invalid token.')


        if request.id:
            contact_to_delete_key = ndb.Key(Contact, request.id)
            if contact_to_delete_key.get():
                contact_to_delete_key.delete()
                return SimpleResponseMsg(success=True)

        return SimpleResponseMsg(success=False)


APPLICATION = endpoints.api_server([FrankApi],
                                   restricted=False)


 类似资料:
  • 我们对App Engine对谷歌云endpoint的支持感到超级兴奋。

  • 问题内容: 这是我的情况: 一个Web应用程序对许多应用程序执行某种SSO 登录的用户,而不是单击链接,该应用就会向正确的应用发布包含用户信息(名称,pwd [无用],角色)的帖子 我正在其中一个应用程序上实现SpringSecurity以从其功能中受益(会话中的权限,其类提供的方法等) 因此,我需要开发一个 自定义过滤器 -我猜想-能够从请求中检索用户信息,通过自定义 DetailsUserSe

  • 问题内容: 我可以使用Google帐户在AppEngine中对用户进行身份验证的方式非常好。 但是,我需要使用 自定义的身份验证登录系统 。 我将有一个AppUsers表,其中包含用户名和加密密码。 我阅读了有关gae会话的内容,但在启动应用安全性方面需要帮助。 如何跟踪经过身份验证的用户会话?设置cookie? 初学者。 问题答案: 您可以使用cookie来做到这一点……其实并不难。您可以使用C

  • 我在spring MVC项目中实现了一个自定义身份验证提供程序。在我自己的重载authenticate()方法中,我实现了自己的身份验证,其中我构造了自己的UserPasswordAuthenticationToken()并返回对象。 现在,上述对象“UserPasswordAuthentictionToken”中的用户ID被匿名化,密码为null,权限设置为授予该用户的权限。 问题: 这是否会导

  • 问题内容: 我正在为Angular 5应用程序创建API。我想使用JWT进行身份验证。 我想使用Spring Security提供的功能,以便我可以轻松地使用角色。 我设法禁用基本身份验证。但是使用时我仍然会收到登录提示。 我只想输入403而不是提示。因此,通过检查令牌标题的“事物”(是否是过滤器?)来覆盖登录提示。 我只想在将返回JWT令牌的控制器中进行登录。但是我应该使用哪种Spring Se

  • 我正在为Angular 5应用程序创建API。我希望使用JWT进行身份验证。 我希望使用spring security提供的特性,以便能够轻松地处理角色。 我只想在返回JWT令牌的控制器中进行的登录。但是我应该使用什么Spring Securitybean来检查用户凭据呢?我可以构建自己的服务和存储库,但我希望尽可能使用spring security提供的特性。 这个问题的简短版本只是: 我如何自