App Engine中的Google Services身份验证,第1部分
項目源代碼
這篇文章背后的動機是,我很難找到以前將這些技術真正聯系在一起的任何示例。 然而,這些技術確實代表了許多想要利用大量Google API服務的Web應用程序的基礎。
為了簡單起見,該演示僅允許用戶通過Google域登錄; 授權訪問用戶的Google文檔服務; 并顯示用戶的Google Docs Word和電子表格文檔的列表。 在本教程中,我會對讀者的專業知識做出一些假設,例如對Java的深入了解。
流程概述
在我們直接進入教程/演示之前,讓我們簡要介紹一下導航流程。
盡管它看起來很復雜,但是主要流程可以總結為:
可以使用相同的方法訪問其他Google服務,例如YouTube(例如,您可以顯示用戶喜歡的視頻的列表)。
環境設定
對于本教程,我使用以下內容:
- Eclipse Indigo Service Release 2以及適用于Eclipse的Google插件(請參閱設置說明 )。
- Google GData Java SDK Eclipse插件版本1.47.1(請參閱設置說明 )。
- Google App Engine 1.6.5版。 早期版本存在一些問題,因此我建議確保您正在使用它。 它應該作為Eclipse的Google插件的一部分自動安裝。
- Objectify版本3.1。 所需的庫已安裝在項目的war / WEB-INF / lib目錄中。
將項目導入Eclipse之后,您的構建路徑應類似于:
App Engine設置應類似于:
您將需要設置自己的GAE應用程序,并指定自己的應用程序ID(請參閱Google GAE開發人員文檔 )。
描述如何使用OAuth訪問谷歌API服務我見過的最好的教程可以找到這里 。 我發現最令人困惑的方面之一是如何獲取放置OAuth請求時所需的必要的消費者密鑰和消費者秘密值。 我完成此操作的方式是:
擁有OAuth使用者密鑰和OAuth使用者密鑰之后 ,您將替換com.zazarie.shared.Constant文件中的以下值:
最后的靜態字符串CONSUMER_KEY =''; 最后的靜態字符串CONSUMER_SECRET =''; 哇,這似乎是很多工作! 但是,這是一次性交易,您不必再次大驚小怪。
代碼演練
既然我們已經完成了OAuth的配置/設置,那么我們就可以深入研究代碼了。 讓我們從查看戰爭目錄的結構開始,您的Web資產位于該目錄中:
listFiles.jsp是您首次進入Web應用程序時顯示的默認JSP頁面。 現在讓我們看一下web.xml文件,看看如何配置它,以及對所有內容都至關重要的servlet過濾器。
<?xml version='1.0' encoding='UTF-8'?><web-app xmlns:xsi='http:www.w3.org2001XMLSchema-instance'xsi:schemaLocation='http:java.sun.comxmlnsjavaee http:java.sun.comxmlnsjavaeeweb-app_2_5.xsd'version='2.5' xmlns='http:java.sun.comxmlnsjavaee'><!-- Filters --><filter><filter-name>AuthorizationFilter<filter-name><filter-class>com.zazarie.server.servlet.filter.AuthorizationFilter<filter-class><filter><filter-mapping><filter-name>AuthorizationFilter<filter-name><url-pattern>html*<url-pattern><filter-mapping><!-- Servlets --><servlet><servlet-name>Step2<servlet-name><servlet-class>com.zazarie.server.servlet.RequestTokenCallbackServlet<servlet-class><servlet><servlet-mapping><servlet-name>Step2<servlet-name><url-pattern>authSub<url-pattern><servlet-mapping><!-- Default page to serve --><welcome-file-list><welcome-file>htmllistFiles.jsp<welcome-file><welcome-file-list><web-app>每當請求位于html目錄中的JSP文件時,就會調用稱為AuthorizationFilter的servlet過濾器。 我們將在稍后介紹的過濾器負責確保用戶已登錄Google,如果是,則確保已為該用戶授予OAuth憑據(即,它將啟動OAuth認證過程(如果需要)。
步驟2的Servlet名稱代表已授予OAuth憑據時Google調用的Servlet-將其視為回調。 我們將對此進行更詳細的介紹。
讓我們更詳細地看一下AuthorizationFilter。
AuthorizationFilter深潛
doFilter方法是在servlet過濾器中進行工作的地方。 這是實現:
@Overridepublic void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) res;HttpSession session = request.getSession();LOGGER.info('Invoking Authorization Filter');LOGGER.info('Destination URL is: ' + request.getRequestURI());if (filterConfig == null)return;get the Google userAppUser appUser = LoginService.login(request, response);if (appUser != null) {session.setAttribute(Constant.AUTH_USER, appUser);}identify if user has an OAuth accessToken - it not, will set in motionoauth procedureif (appUser.getCredentials() == null) {need to save the target URI in session so we can forward to it whenoauth is completedsession.setAttribute(Constant.TARGET_URI, request.getRequestURI());OAuthRequestService.requestOAuth(request, response, session);return;} elsestore DocService in the session so it can be reusedsession.setAttribute(Constant.DOC_SESSION_ID,LoginService.docServiceFactory(appUser));chain.doFilter(request, response);}除了通常的家務管理之外,主要邏輯還從以下幾行開始:
AppUser appUser = LoginService.login(request,response);
稍后我們將看到,LoginService負責將用戶登錄到Google,并在本地BigTable數據存儲區中創建用戶。 通過將用戶存儲在本地,我們可以存儲用戶的OAuth憑據,從而無需用戶每次訪問受限制/過濾的頁面時都必須授予權限。
LoginService返回用戶(AppUser對象)后,我們將該用戶對象存儲到會話中(注意:要啟用會話,必須在appengine-web.xml文件中將session-enabled設置為:)
session.setAttribute(Constant.AUTH_USER,appUser);
然后,我們檢查OAuth憑據是否與該用戶相關聯:
如果(appUser.getCredentials()== null){
session.setAttribute(Constant.TARGET_URI,request.getRequestURI());
OAuthRequestService.requestOAuth(請求,響應,會話);
返回;
}其他 session.setAttribute(Constant.DOC_SESSION_ID,LoginService.docServiceFactory(appUser));
如果getCredentials()返回null,則尚未為用戶分配OAuth憑據。 這意味著OAuth流程需要啟動。 由于此過程分為兩步,即將請求發布到Google,然后通過回調(上面提到的Step2 servlet)檢索結果,因此我們需要存儲目標URL,以便一旦授權后就可以將用戶重定向到該URL。處理完成。 這是通過使用setAttribute方法將請求的URL存儲到會話中來完成的。
然后,我們通過調用OAuthRequestService.requestOAuth()方法開始OAuth流程(詳細信息將在下面討論)。
如果getCredentials()返回一個非null值,則表明我們已經從數據存儲區中的本地AppUser條目中獲取了用戶的OAuth憑據,我們只需將其添加到會話中,以便以后使用。
LoginService深入研究
LoginService類有一個稱為login的主要方法,其后是一堆JPA幫助器方法,用于保存或更新數據存儲區中的本地用戶。 我們將重點放在login()上,因為這是大多數業務邏輯所在的位置。
public static AppUser login(HttpServletRequest req, HttpServletResponse res) {LOGGER.setLevel(Constant.LOG_LEVEL);LOGGER.info('Initializing LoginService');String URI = req.getRequestURI();UserService userService = UserServiceFactory.getUserService();User user = userService.getCurrentUser();if (user != null) {LOGGER.info('User id is: '' + userService.getCurrentUser().getUserId()+ ''');String userEmail = userService.getCurrentUser().getEmail();AppUser appUser = (AppUser) req.getSession().getAttribute(Constant.AUTH_USER);if (appUser == null) {LOGGER.info('appUser not found in session');see if it is a new userappUser = findUser(userEmail);if (appUser == null) {LOGGER.info('User not found in datastore...creating');appUser = addUser(userEmail);} else {LOGGER.info('User found in datastore...updating');appUser = updateUserTimeStamp(appUser);}} else {appUser = updateUserTimeStamp(appUser);}return appUser;} else {LOGGER.info('Redirecting user to login page');try {res.sendRedirect(userService.createLoginURL(URI));} catch (IOException e) {e.printStackTrace();}}return null;}我們要做的第一件事是使用Google UserService類確定用戶是否登錄到Google:
UserService userService = UserServiceFactory.getUserService();
用戶用戶= userService.getCurrentUser();
如果Google的調用返回的User對象為null,則不會登錄該用戶,并使用以下命令將其重定向到登錄頁面:
res.sendRedirect(userService.createLoginURL(URI));
如果用戶已登錄(即不為null),則下一步是確定該用戶是否存在于本地數據存儲中。 這是通過使用appUser = findUser(userEmail)查找用戶及其登錄的Google電子郵件地址來完成的。 由于JPA / Objectify并不是本教程的主要討論點,因此我將不介紹該方法的工作原理。 但是, Objectify網站上有一些很棒的教程/文檔。
如果用戶不在本地,則使用Google的電子郵件地址填充該對象,并使用appUser = addUser(userEmail)創建該對象。 如果用戶確實存在,我們僅出于登錄目的而更新登錄時間戳。
OAuthRequestService深入研究
您可能會回憶起,在本地設置了用戶之后,AuthorizationFilter便會檢查該用戶是否已授予OAuth憑據。 如果不是,則調用OAuthRequestService.requestOAuth()方法。 如下圖所示:
為了簡化OAuth的使用,Google提供了一組我們正在使用的Java幫助器類。 我們需要做的第一件事是設置使用者憑據(獲取這些憑據之前已經討論過):
GoogleOAuthParameters oauthParameters =新的GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(Constant.CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(Constant.CONSUMER_SECRET);
然后,我們使用以下命令設置OAuth請求的范圍:
oauthParameters.setScope(Constant.GOOGLE_RESOURCE);
Constant.GOOGLE_RESOURCE解析為https://docs.google.com/feeds/的位置。 發出OAuth請求時,請指定您試圖獲得訪問權限的資源范圍。 在這種情況下,我們嘗試訪問Google文檔(每個服務的GData API都提供了作用域URL)。 接下來,我們確定希望Google返回答復的位置。
oauthParameters.setOAuthCallback(Constant.OATH_CALLBACK);
無論我們是以開發人員模式在本地運行還是部署到Google App Engine,此值都會更改。 在Constant接口中定義值的方法如下:
//用于在GAE上運行
//最終靜態字符串OATH_CALLBACK ='http://tennis-coachrx.appspot.com/authSub';
//用于本地測試
最后的靜態字符串OATH_CALLBACK ='http://127.0.0.1:8888/authSub';
然后,使用Google的幫助程序簽署請求時:
GoogleOAuthHelper oauthHelper =新的GoogleOAuthHelper(新的OAuthHmacSha1Signer());
然后,我們生成用戶將導航到的URL,以授權對資源的訪問。 這是使用以下方法動態生成的:
字符串rovalPageUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);
最后一步是向用戶提供鏈接,以便他們可以導航到該URL來批準請求。 這是通過構造一些簡單HTML來完成的,這些HTML使用res.getWriter()。print()輸出。
用戶授予訪問權限后,Google便會調用由URL參數/ authSub標識的servlet,該參數對應于servlet類RequestTokenCallbackServlet。 接下來,我們將對此進行檢查。
RequestTokenCallbackServlet深入研究
該servlet使用Google OAuth幫助程序類來生成所需的訪問令牌和秘密訪問令牌,這些訪問令牌和秘密訪問令牌將在隨后對Google API文檔服務的調用中被使用。 這是從Google接收回叫響應的doGet方法:
Google GoogleOAuthHelper用于執行填充我們感興趣的兩個值所需的內務處理任務:
字符串accessToken = oauthHelper.getAccessToken(oauthParameters);
字符串accessTokenSecret = oauthParameters.getOAuthTokenSecret();
獲得這些值之后,我們便從數據存儲區中重新查詢用戶對象,并將這些值保存到AppUser.OauthCredentials子類中:
appUser = LoginService.getById(appUser.getId());
appUser = LoginService.updateUserCredentials(appUser, 新的OauthCredentials(accessToken,accessTokenSecret)); req.getSession()。setAttribute(Constant.DOC_SESSION_ID, LoginService.docServiceFactory(appUser));
此外,您還會看到它們也存儲在會話中,因此當向Google Docs發出API請求時,我們可以隨時使用它們。
現在我們有了所需的一切,我們只需將用戶重定向到他們最初請求的資源即可:
RequestDispatcher調度程序= req.getRequestDispatcher((String)req
.getSession()。getAttribute(Constant.TARGET_URI));
dispatcher.forward(req,resp);
現在,當他們訪問列出他們的文檔的JSP頁面時,一切都會正常!
這是最終產品的截屏演示:
希望您喜歡本教程和演示-期待您的評論!
繼續本教程的第二部分 。
參考:來自Jeff's SOA Ruminations博客的JCG合作伙伴 Jeff Davis 對Google App Engine中的Google Services進行身份驗證 。
翻譯自: https://www.javacodegeeks.com/2012/06/google-services-authentication-in-app.html
總結
以上是生活随笔為你收集整理的App Engine中的Google Services身份验证,第1部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最强安卓模拟器手机版(最强安卓模拟器)
- 下一篇: ADF任务流:页面片段的托管bean范围